[把你的理性思维慢慢变成条件反射]
本文,我们讲介绍装饰模式,文章主题结构与上位一致。惯例,先来看看我们示例工程的环境:
操作系统:win7 x64
其他软件:eclipse mars,jdk7
-------------------------------------------------------------------------------------------------------------------------------------人们的服装搭配问题、家庭装修问题、客户定制化的功能问题等。本文以“人们的服装搭配问题”为例进行说明。
要点一:以人为核心。
要点二:服装搭配不改变核心。
要点三:搭配按需变化,具有不确定性。
package com.csdn.ingo.gof_Decorator.base; public class Person { private String name; public Person(String name){ this.name = name; } public void wearTShirts(){ System.out.println("大T恤"); } public void wearBigTrouse(){ System.out.println("垮裤"); } public void wearSneakers(){ System.out.println("球鞋"); } public void wearSuit(){ System.out.println("西装"); } public void wearTie(){ System.out.println("领带"); } public void wearLeatherShoes(){ System.out.println("皮鞋"); } public void Show(){ System.out.println("装扮后的"+name); } } 创建Window.java文件,具体内容如下:
package com.csdn.ingo.gof_Decorator.base; public class Window { public static void main(String[] args) { Person ingo = new Person("Ingo"); System.out.println("第2种装扮:"); ingo.wearTShirts(); ingo.wearBigTrouse(); ingo.wearSneakers(); ingo.Show(); System.out.println("第2种装扮:"); ingo.wearSuit(); ingo.wearTie(); ingo.wearLeatherShoes(); ingo.Show(); } }
虽然代码工程正确,但违反了我们前文介绍的“单一职责原则”:Person的创建与装饰功能混合在一起。违反“开闭原则”:由于装饰的功能经常处于变动状态,因此,对于某个功能的修改可能扩展到其他装饰功能当中。故,base包下的这种写法是错误的。
创建Finery.java文件,具体内容如下:
package com.csdn.ingo.gof_Decorator.one; public abstract class Finery { public abstract void show(); } 创建BigTrouser.java,LeatherShoes.java,Sneakers.java,Suit.java,Tie.java,TShirts.java文件,在此仅列举BigTrouser.java文件,具体内容如下:
package com.csdn.ingo.gof_Decorator.one; public class BIgTrouser extends Finery { @Override public void show() { System.out.println("垮裤"); } } 创建Person.java文件,具体内容如下:
package com.csdn.ingo.gof_Decorator.one; public class Person { private String name; public Person(String name){ this.name = name; } public void Show(){ System.out.println("装扮的"+name); } } 创建Window.java,具体内容如下:
package com.csdn.ingo.gof_Decorator.one; public class Window { public static void main(String[] args) { Person ingo = new Person("Ingo"); System.out.println("第1种装扮:"); Finery tshirts = new TShirts(); Finery bigt = new BIgTrouser(); Finery sneaker = new Sneakers(); tshirts.show(); bigt.show(); sneaker.show(); ingo.Show(); System.out.println("第2种装扮:"); Finery suit = new Suit(); Finery tie = new Tie(); Finery lea = new LeatherShoes(); suit.show(); tie.show(); lea.show(); ingo.Show(); } }
这种写法将装饰的内容一个一个的都列举了出来,这种做法将导致客户端产生非常多的对象声明,方法调用等,正如上文展示的那样。并且导致后期维护成本的急剧上升。因此,这种采用继承方式的设计也是错误的。
创建Finery.java文件,具体内容如下:
package com.csdn.ingo.gof_Decorator.three; public class Finery extends Person { protected Person component; public void Decorate(Person component){ this.component = component; } @Override public void show(){ if(component!=null){ component.show(); } } } 创建BigTrouser.java,LeatherShoes.java,Sneakers.java,Suit.java,Tie.java,TShirts.java文件,在此仅列举BigTrouser.java文件,具体内容如下:package com.csdn.ingo.gof_Decorator.three; public class BIgTrouser extends Finery { @Override public void show() { System.out.println("垮裤"); super.show(); } } 创建Window.java,具体内容如下:
package com.csdn.ingo.gof_Decorator.three; public class Window { public static void main(String[] args) { Person ingo = new Person("Ingo"); System.out.println("第1种装扮:"); TShirts tshirts = new TShirts(); BIgTrouser bigt = new BIgTrouser(); Sneakers sneaker = new Sneakers(); tshirts.Decorate(ingo); bigt.Decorate(tshirts); sneaker.Decorate(bigt); sneaker.show(); System.out.println("第2种装扮:"); Suit suit = new Suit(); Tie tie = new Tie(); LeatherShoes lea = new LeatherShoes(); suit.Decorate(ingo); tie.Decorate(suit); lea.Decorate(tie); lea.show(); } }
装饰模式:动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
组成部分:Component(抽象部件),ConcreteComponent(具体部件),Decorator(抽象装饰),ConcreteDecorator(具体装饰)四部分组成。
Component.java文件:
package com.csdn.ingo.gof_Decorator.two; public abstract class Component { public abstract void Operation(); } ConcreteComponent.java文件:
package com.csdn.ingo.gof_Decorator.two; public class ConcreteComponent extends Component { @Override public void Operation() { System.out.println("具体对象的操作"); } } ConcreteDecoratorA.java文件:
package com.csdn.ingo.gof_Decorator.two; public class ConcreteDecoratorA extends Decorator { private String addedState;//本类独有,以区别于B @Override public void Operation() { super.Operation(); addedState = "New State"; System.out.println("具体装饰对象A的操作"); } } package com.csdn.ingo.gof_Decorator.two; public class ConcreteDecoratorB extends Decorator { @Override public void Operation() { super.Operation(); AddedBehavior(); System.out.println("具体装饰对象A的操作"); } private void AddedBehavior() { //本类独有,以区别于A } } Decorator.java文件:
package com.csdn.ingo.gof_Decorator.two; public abstract class Decorator extends Component { protected Component component; public void setComponent(Component component){ this.component = component; } @Override public void Operation() { if(component!=null){ component.Operation();//调用原有业务操作 } } }
在抽象装饰类Decorator中定义了一个Component类型的对象component,维持一个对抽象构件对象的引用,并可以通过构造方法或Setter方法将一个Component类型的对象注入进来,同时由于Decorator类实现了抽象构件Component接口,因此需要实现在其中声明的业务方法operation(),需要注意的是在Decorator中并未真正实现operation()方法,而只是调用原有component对象的operation()方法,它没有真正实施装饰,而是提供一个统一的接口,将具体装饰过程交给子类完成。
Window.java文件: package com.csdn.ingo.gof_Decorator.two; public class Window { public static void main(String[] args) { ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); d1.setComponent(c); d2.setComponent(d1); d2.Operation(); } }答:当只有一个ConcreteComponent类,而没有抽象的Component类时,那么Decorator类可以是ConcreteComponent的一个子类。同理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个独立的Decorator类,而可以把Decorator和ConcreteDecorator合并为一个类。因此,在本例中服饰类直接作为人的子类。
在上文的例子“服装搭配”中,所有的具体子类都是需要最终显示出来的。但是,有些“隐含的装饰品”仅仅存在在装饰的过程当中,最终结果并不会体现出来,如本文的,ingo通过一系列的装饰之后,乘坐各种交通工具前往约定地点的过程,就仅仅在“过程中”出现,到达之后就会消失。换句话说,某些操作仅仅存在过程中,并且,该操作与其他装饰步骤无任何调用耦合关系。类似的场景还有,单据的审批过程,在最终的审批单中并不会显示出审批过程一样。等等类似的场景。
解决步骤:
对于“隐含的装饰品”需要使用ConcreteDecorator来进行。即,客户端需要显示声明一个具体的“交通工具”对象来进行装饰,之后再将对象交还给装饰流程。如此的好处是给系统设计带来了更多的灵活性。
特别注意:
这里的“过程中存在”的概念,即过程只有一次,该装饰过程也只能发生一次,不可多次调用。
在不影响其他对象的条件下,为已有功能动态地添加更多的功能,这些功能通常仍以原有的类作为核心职责或主要行为。
当不能使用继承的方式作为扩展,或者,不适合使用继承的方式进行扩展与维护时。(原因:继承会产生大量的子类,由此产生管理问题。另外,某些类不能够内继承扩展)
-------------------------------------------------------------------------------------------------------------------------------------
至此,被说了很多遍的设计模式---装饰模式 结束
参考资料:
图书:《大话设计模式》
其他博文:http://blog.csdn.NET/lovelion/article/details/7563445