簡體   English   中英

這是裝飾者還是策略模式,或者兩者都不是?

[英]Is this a decorator or a strategy pattern, or neither of the two?

我有以下界面。

PowerSwitch.java

public interface PowerSwitch {
    public boolean powerOn();
    public boolean powerOff();
    public boolean isPowerOn();
}

上面的接口應該包含可以從中派生出任何其他功能的最小方法集,以便盡可能簡單地添加其他PowerSwitch實現。

我想在運行時向PowerSwitch接口添加功能(裝飾器做什么),創建一個包含PowerSwitch實例組合的類並添加新方法,如下面的兩個toggleOnOff()方法。 這樣我只需要實現兩次切換方法,它將適用於所有PowerSwitch實現。

這被認為是一種好/壞的做法嗎? 如果不好,還有其他建議嗎?

它並不真正符合裝飾器模式,因為它增加了額外的方法。 它是策略模式還是組合模式? 或者它有另一個模式名稱? 有“界面裝飾”這樣的東西嗎?

PowerSwitchDecorator.java

public class PowerSwitchDecorator {
    private PowerSwitch ps;

    public PowerSwitchDecorator(PowerSwitch ps) {
        this.ps = ps;
    }

    public void toggleOnOff(int millis) throws InterruptedException{
        powerOn();
        Thread.sleep(millis);
        powerOff();
    }

    public void toggleOnOff(){
    powerOn();
    powerOff();
    }

    public boolean powerOn() {
        return ps.powerOn();
    }

    public boolean powerOff() {
        return ps.powerOff();
    }

    public boolean isPowerOn() {
        return ps.isPowerOn();
    }
}

實際上,任何想要使用toggleOnOff(int)toggleOnOff()方法的代碼都需要PowerSwitchDecorator的實例,而不是PowerSwitch 這種方式破壞了裝飾者的目的,這對客戶來說應該是透明的。

如果您希望所有實現都具有這些方法,則應將它們包含在PowerSwitch界面中。

然后,正如@Ani建議的那樣,您可以修改上面的PowerSwitchDecorator來擴展PowerSwitch以便您可以這樣做:

PowerSwitch switch = new PowerSwitchDecorator(new ConcretePowerSwitch());
switch.toggleOnOff();

現在你有一個PowerSwitch類型的變量和PowerSwitchDecorator的功能。

編輯:請注意,如果滿足您的需求,您應該只使用已建立的模式。 如果它適合您,您可以使用您顯示的方法。 無需將其鞋拔成特定圖案。

你想傳遞什么類型的物體? 你想在API中使用這樣的方法:

void connect(PowerSwitch powerSwitch, Appliance appliance);

或者像這樣的方法:

void connect(PowerSwitchDecorator powerSwitch, Appliance appliance);

(對不起,他們不是很好的例子)

如果你想要前者,那么每個人都必須手動“裝飾”他們的PowerSwitch只是為了獲得一些方便的方法。 現在對您來說可能很方便,但我認為對您的代碼用戶來說不方便,他們可能不會為此煩惱。 如果你想要后者,你必須在方法簽名中使用PowerSwitchDecorator類型,這往往意味着你總是處理PowerSwitchDecorator而不是原始PowerSwitch es。

在運行時需要增強PowerSwitch實例的情況下,這是一個很好的做法。 我建議你在裝飾器中實現PowerSwitch接口。 裝飾器模式的另一個名稱是代理模式。

您可以在擴展PowerSwitch接口的另一個接口中定義擴展方法。 當需要調用這些擴展方法時,這將避免依賴於裝飾器。

當您需要在編譯時增強或重新定義行為時,擴展類是一種很好的做法。

您的PowerSwitchDecorator類不是裝飾器。 即使命令類似於Command_pattern,您的實現也接近於Strategy_pattern

Decorator模式中, Decorator實際上實現了接口(即Component ),而你的類卻沒有做同樣的事情。

看看班級圖

在此輸入圖像描述

在上圖中, Component是一個接口。 Decorator實現了Component接口,並包含了Composition的接口。 查看成員變量 - component

請參閱以下問題以便更好地理解:

IO的裝飾模式

戰略模式的現實世界范例

如果裝飾器也實現了PowerSwitch接口,它真的會是一個裝飾器。 我將其描述為對象聚合。

它既不是模式。

裝飾器旨在包裝對象並擴展已存在的功能,使得接口對客戶端透明。 BufferedInputstream就是一個例子。 請注意,Decorator應該實現與要包裝的Type相同的接口。

//Let Type be the interface that both the Decorator and DecoratedClass implements
Type yourInstance = new Decorator(new DecoratedClass());

請注意與Proxy-pattern的區別,其中主要目的是控制對對象的訪問,而不一定是通過包裝另一個對象。 在這種情況下,您還可以讓代理實現相同的接口。

幾種模式通常看起來相似,不同之處在於它們的使用意圖。 這是關於這個主題的更一般的主題: 何時以及如何應用策略模式而不是裝飾模式?

使用您的代碼,還沒有真正的區別。 它看起來像一個策略,因為PowerSwitchDecorator只是將工作(即算法)委托給PowerSwitch。 如果這是你的意圖,並且有不同的PowerSwitch以不同的方式切換,那么策略模式是你的選擇。

如果您有一組PowerSwitch,每個都以一種輕微的方式增強切換(裝飾切換)並且這些PowerSwitch可以嵌套,那么您正在實現一個decorater。 如前所述,在這種情況下,您還需要裝飾器作為類型層次結構的一部分。

我會說這不是模式。

裝飾圖案

裝飾器模式用於擴展現有實現的行為。 以圖形窗口為例,您可能希望有一個帶滾動條的窗口。 然后你可以有一個類

public class ScrollBarsWindow : Window
{
     private Window windowToDecorate;
     public ScrollBarsWindow(Window windowToDecorate)
     {
         this.windowToDecorate = windowToDecorate;
     }

     public void Draw()
     {
         windowToDecorate.Draw();
         DrawScrollBars();
     }

     public void DrawScrollBars()
     { Draw the scroll bars }
 }

戰略模式

策略模式用於根據所選策略執行不同的操作。 假設你正在煮咖啡。 你可以有類似的東西:

public interface IMakeCoffeeStrategy
{
    public Coffee MakeCoffee();
}

public class CappuccinoStrategy : IMakeCoffeeStrategy
{
    public Coffee MakeCoffee { make your cappuccion }
}

public class LatteStrategy : IMakeCoffeeStrategy
{
    public Coffee MakeCoffee { make your latte }
}

public class Context
{
    private IMakeCoffeeStrategy strategy;
    public Context(IMakeCoffeeStrategy strategy)
    {
        this.strategy = strategy;
    }

    public Coffee MakeSomeCoffee()
    {
        return strategy.MakeCoffee();
    }
}

並使用它

public class MyCoffeeMachine
{
    public Coffee MakeCoffee(CoffeeType coffeeType)
    {
        if(coffeeType == CoffeeType.Latte)
            return new Context(new LatteStrategy()).MakeSomeCoffee();
        else if(coffeeType == CoffeeType.Cappuccino)
            return new Context(new CappuccinoStrategy()).MakeSomeCoffee();

       ...
    }
}

閱讀以下鏈接以獲取更多信息:

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM