题目:写一个给人搭配不同服饰的系统,就是那种可以换各种各样衣服裤子的个人形象系统。简单点,用控制台实现。
第一版:
public class Person { private String name; public Person(String name){ this.name = name; } public void wearShoes(){ System.out.println("破球鞋"); } public void wearJeans(){ System.out.println("牛仔裤"); } public void wearShirts(){ System.out.println("T恤"); } public void wearTie(){ System.out.println("打领带"); } public void show(){ System.out.println("装扮的" + name); } public static void main(String[] args){ Person xiaoming = new Person("小明"); System.out.println("第一种装扮:"); xiaoming.wearShoes(); xiaoming.wearJeans(); xiaoming.show(); System.out.println("第二种装扮:"); xiaoming.wearShoes(); xiaoming.wearShirts(); xiaoming.wearTie(); xiaoming.show(); } }
功能是实现了,但如果要增加“超人”的装扮,就需要修改“Person”类,这违背了“开放封闭原则”。所以应该把这些服饰类都写成子类。
第二版:
代码结构图
public abstract class Finery { public abstract void show(); } class TShirts extends Finery{ public void show() { System.out.println("大T恤"); } } class Shoes extends Finery{ public void show() { System.out.println("破球鞋"); } } class Tie extends Finery{ public void show() { System.out.println("打领带"); } }
public class Person2 { private String name; public Person2(String name){ this.name = name; } public void show(){ System.out.println("装扮的" + name); } public static void main(String[] args) { // TODO Auto-generated method stub System.out.println("第一种装扮:"); Person2 xiaohua = new Person2("小华"); TShirts ts = new TShirts(); Shoes shoes = new Shoes(); Tie tie = new Tie(); ts.show(); shoes.show(); tie.show(); xiaohua.show(); } }
现在代码确实做到了“服饰”类与“人”类的分离,但还是有问题存在。这是一个一个拼凑出来的。应该在内部组装完毕,然后再显示出来,这有点像建造者模式,但却不是。建造者模式要求建造的过程是稳定的,而我们这个例子建造过程不是稳定的。通过服饰组合出一个有个性的人完全有无数种方式,并非是固定的。我们需要把所需的功能按正确的顺序串联起来进行控制,这可以用一个有意思的设计模式来实现-装饰模式。
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
装饰模式结构图
装饰模式是利用Decorator来对对象进行包装的。这样每个对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链中。
那如何用装饰模式改写上面的例子呢?这里得注意一下,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类就可以是ConcreteComponent的一个子类。同样的道理,如果只有一个ConcreteDecorator类,就没必要建立一个Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
第三版:
代码结构图
Component类
public abstract class Component { public abstract void show(); }
ConcreteComponent类
public class Person3 extends Component{ private String name; public Person3(String name){ this.name = name; } public void show(){ System.out.println("装扮de" + name); } public static void main(String[] args){ Finery3 finery = new Tie3(new TShirts3(new Person3("小黑"))); finery.show(); } }
Decorator类
public class Finery3 extends Component{ protected Component component; public Finery3(Component component){ this.component = component; } public void decorate(Component component){ this.component = component; } public void show(){ if(component != null){ component.show(); } } }
ConcreteDecorator类
public class Tie3 extends Finery3{ public Tie3(Component component){ super(component); } public void show(){ System.out.println("打领带"); super.show(); } }
public class TShirts3 extends Finery3{ public TShirts3(Component component){ super(component); } public void show(){ System.out.println("穿T恤"); super.show(); } }
从Person3类的main方法可以看到,现在我们可以灵活的搭配服饰了。
总结:
装饰模式是为已有功能动态地添加更多功能的一种方式。那到底什么时候该用它呢?在起初的设计中,当系统需要新功能时,是向旧的类中添加新的代码,这些新代码通常装饰了原有类的核心职责或主要行为。但这种做法问题在于增加了主类的复杂度,而新加入的东西仅仅是为了满足一些只在特定条件下才会执行的行为的需要。而装饰模式提供了一种非常好的解决方案,它把要装饰的功能单独地放在一个类中,并让装饰类包装它所要装饰的对象,因此,当需要执行特殊行为的时候,客户代码就可以在运行的时候根据需要有选择地、按顺序地使用装饰功能包装对象了。这样做最大的好处就是把类的核心职责和装饰功能区分开了,而且可以去除相关类中重复的装饰逻辑。