2017-02-18 36 views
4

在裝飾模式,我很困惑如何使用裝飾方法。我已經瞭解到,裝飾器模式用於將函數添加到基類。但是我只能調用最外層的裝飾器的方法,所以如果在接口中沒有提到,我應該如何使用inner-decorator的方法。我不擅長英語,所以我編寫代碼來演示我的問題。裝修模式與合同

public class OrderSystem { 
    public static void main(String[] args) { 
     Pancakes pancakes = new MixedPancakes(); 
     pancakes = new Ham(pancakes); 
     ((Ham) pancakes).hamState(); // call hamState 
     pancakes = new Egg(pancakes); 
     ((Egg) pancakes).eggState(); 
     // i can't call hamState() there because it not belong to Egg 

     Pancakes pancakes1 = new Ham(new Egg(new FlourPancakes())); 
     // similarly, i can't use eggState() there. 
     System.out.println("訂單:" + pancakes1.getDescription()); 
     System.out.println("價格:" + pancakes1.cost()); 
    } 
} 

interface Pancakes { 
    public abstract String getDescription(); 

    public abstract int cost(); 
} 

abstract class Seasoning implements Pancakes { 
    @Override 
    public abstract String getDescription(); 
} 

class Ham extends Seasoning { 

    Pancakes pancakes; 

    public Ham(Pancakes pancakes) { 
     this.pancakes = pancakes; 
    } 

    @Override 
    public int cost() { 
     return pancakes.cost() + 2; 
    } 

    @Override 
    public String getDescription() { 
     return pancakes.getDescription() + "+火腿"; 
    } 

    public void hamState() { 
     System.out.println("火腿切碎"); 
    } 

} 

class Egg extends Seasoning { 

    Pancakes pancakes; 

    public Egg(Pancakes pancakes) { 
     this.pancakes = pancakes; 
    } 

    @Override 
    public int cost() { 
     return pancakes.cost() + 1; 
    } 

    @Override 
    public String getDescription() { 
     return pancakes.getDescription() + "+雞蛋"; 
    } 

    public void eggState() { 
     System.out.println("雞蛋打碎"); 
    } 
} 

class MixedPancakes implements Pancakes { 

    @Override 
    public String getDescription() { 
     return "五穀雜糧煎餅"; 
    } 

    @Override 
    public int cost() { 
     return 6; 
    } 
} 

class FlourPancakes implements Pancakes { 

    @Override 
    public String getDescription() { 
     return "白麪煎餅"; 
    } 

    @Override 
    public int cost() { 
     return 5; 
    } 
} 

當我問註釋,當裝飾用另一個包裹,只在接口中聲明的方法(如cost()getDescription())將工作,而另一種方法將不再被調用。我想如果我創造一個士兵,如果我使用槍裝飾他將是shoot() - 槍的功能。如果我明天用劍裝飾他,他不僅可以shoot(),而且還有cut() - 劍的功能。我可以用裝飾模式實現它嗎? 對於任何誤解和感謝您的幫助,我很抱歉。

+10

裝飾者的要點不是添加方法。這是爲了使裝飾對象的方法做更多*或*不同*。裝飾器應該與正在裝飾的對象具有相同的類型。例如,一個BufferedReader裝飾另一個讀者。它的read()方法委託給裝飾閱讀器的read()方法,但在頂部添加緩衝區。 –

+2

@JBNizet,我認爲這應該是一個答案,而不是評論。 –

+0

@GrzegorzGórkiewicz那不會回答這個問題。 – CKing

回答

1

正如人們在您的問題的評論中提到的那樣,裝飾者模式並不完全如此。

使用你的士兵例如,裝飾會的工作是這樣的:

public abstract class Soldier { 
    public abstract void attack(); 
} 

public abstract class SoldierDecorator extends Soldier { 

    protected Soldier soldier; 

    public SoldierDecorator(Soldier soldier) { 
     this.soldier = soldier; 
    } 

    @Override 
    public abstract void attack(); 
} 

然後

public class SoldierWithGun extends SoldierDecorator { 

    public SoldierWithGun(Soldier soldier) { 
     super(soldier); 
    } 

    @Override 
    public void attack() { 
     soldier.attack(); 
     shootWithTheGun(); 
    } 

    private void shootWithTheGun() { 
     System.out.println("Shooting with the gun..."); 
    } 
} 

public class SoldierWithSword extends SoldierDecorator { 

    public SoldierWithSword(Soldier soldier) { 
     super(soldier); 
    } 

    @Override 
    public void attack() { 
     soldier.attack(); 
     cutWithSword(); 
    } 

    private void cutWithSword() { 
     System.out.println("Cutting with the sword..."); 
    } 
} 

從裝飾通過你的士兵裝飾將加強自己的攻擊;

現在添加行爲/方法,您可以使用普通舊式繼承。

你可以通過擴展類來添加行爲,BaseSoldier可以行走,但SoldierWithGun可以擴展BaseSoldier,增加一種除步行拍攝的方法。

您可以使用接口來確保某些功能在實現它們的類中可用。

它不完全是你想要的「裝飾」,但我認爲這是你想要做的事。