装饰模式

参考
装饰模式优缺点
装饰模式游戏例子
设计模式(九)装饰模式(Decorator)

假如有个食物类,不同的做法蒸炒煎炸要生成不同的基类。就是四个子类:蒸食物、炒食物,煎食物,炸食物。如果还要有两种做法的子类呢,还要写蒸炒食物,蒸煎食物……三种做法的更夸张,子类多到爆炸。并且为了应对不同情况,要把所有可能用到的子类都提前写出来,而不是到使用时再随时写。
处理办法:
食物类增加四个属性来标记做法:是否蒸,是否炒,是否煎,是否炸……
那要是有蒸两遍的呢?看来这个属性不能用bool类型,还要用int类型。
当然这样做,对应不同的做法组合,处理方法里要写很多if判断上述的四个属性组合,去做对应的逻辑。食物类也因此变得庞大,逻辑超多。如果需要40个属性,甚至400个属性呢……这种直接在基类中处理所有逻辑也违反了开放封闭原则,即基类是可扩展的,但不能修改。可以预见到,随着食物的做法增多,必然要不停地修改基类,以及基类的if判断。

有没有办法做到,生成一个食物的子类,即满足子类要求,又可以处理不同的做法呢。答案就是组合,即设计模式中的装饰模式。

  • abstract class Food食物类
    function todo()
  • Chicken extends Food鸡肉类
  • Duck extends Food鸭肉类
  • FoodDecoration extends Food
  • SteameFood extends FoodDecoration//子类蒸食物,仍然是Food的子类
    private Food food;//使用构造方法传入的变量进行组合
    public SteameFood(Food f){
    this.food = f;
    }
    override function todo(){
    //food.todo()
    //蒸
    }
  • RoastFood extends FoodDecoration//子类烤食物,仍然是Food的子类
    private Food food;//使用构造方法传入的变量进行组合
    public RoastFood(Food f){
    this.food = f;
    }
    override function todo(){
    //food.todo()
    //烤
    }

运行时就可以自由组合了:

// 测试单纯的食物
Food f1 = new Chicken();
System.out.println(f1.getDesc());
System.out.println("----------------------");

// 测试单重修饰的食物
RoastFood rf = new RoastFood(f1);
System.out.println(rf.getDesc());
System.out.println("----------------------");

// 测试多重修饰的食物
SteamedFood sf = new SteamedFood(rf);
System.out.println(sf.getDesc());

执行结果:  
鸡肉
----------------------
烤鸡肉
----------------------
蒸烤鸡肉

可以看出,N种做法只要N个子类。使用的时候多重装饰即可,自己安排好装饰顺序。

你可能感兴趣的:(装饰模式)