参考http://www.cnblogs.com/xinye/p/3910149.html
http://www.2cto.com/kf/201512/455764.html
假如有个食物类,不同的做法蒸炒煎炸要生成不同的基类。就是四个子类:蒸食物、炒食物,煎食物,炸食物。如果还要有两种做法的子类呢,还要写蒸炒食物,蒸煎食物……三种做法的更夸张,子类多到爆炸。并且为了应对不同情况,要把所有可能用到的子类都提前写出来,而不是到使用时再随时写。
处理办法:
食物类增加四个属性来标记做法:是否蒸,是否炒,是否煎,是否炸……
那要是有蒸两遍的呢?看来这个属性不能用bool类型,还要用int类型。
当然这样做,对应不同的做法组合,处理方法里要写很多if判断上述的四个属性组合,去做对应的逻辑。食物类也因此变得庞大,逻辑超多。如果需要40个属性,甚至400个属性呢……这种直接在基类中处理所有逻辑也违反了开放封闭原则,即基类是可扩展的,但不能修改。可以预见到,随着食物的做法增多,必然要不停地修改基类,以及基类的if判断。
有没有办法做到,生成一个食物的子类,即满足子类要求,又可以处理不同的做法呢。答案就是组合,即设计模式中的装饰模式。
1.abstract class Food食物类
function todo()
2.Chicken extends Food鸡肉类
3.Duck extends Food鸭肉类
4.FoodDecoration extends Food
5.SteameFood extends FoodDecoration//子类蒸食物,仍然是Food的子类
private Food food;//使用构造方法传入的变量进行组合
public SteameFood(Food f){
this.food = f;
}
override function todo(){
//food.todo()
//蒸
}
6.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个子类。使用的时候多重装饰即可,自己安排好装饰顺序。