简单装扮
需求:要求写一个可以给人搭配不同的服饰的系统,比如类似QQ、网络游戏或论坛都有的Avatar系统。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40/** * 需求:要求写一个可以给人搭配不同的服饰的系统,比如类似QQ、网络游戏或论坛都有的Avatar系统。 */ public class Person { private String name; public Person(String name) { this.name = name; } public void wearTShirts() { System.out.print("大T恤 "); } public void wearBigTrouser() { System.out.print("垮裤 "); } public void wearSneakers() { System.out.print("破球鞋 "); } public void wearSuit() { System.out.print("西装 "); } public void wearTie() { System.out.print("领带 "); } public void wearLeatherShoes() { System.out.print("皮鞋 "); } public void show() { System.out.print("装扮的" + name); } }
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Client { public static void main(String[] args) { Person person = new Person("张无忌"); System.out.println("第一种装扮:"); person.wearTShirts(); person.wearBigTrouser(); person.wearSneakers(); person.show(); System.out.println(); System.out.println("第二种装扮:"); person.wearSuit(); person.wearTie(); person.wearLeatherShoes(); person.show(); } }
问题:如果需要增加“超人”的装扮,该如何做呢?虽然修改Person类就可以了,但是违背了开闭原则,所以应该将这些服饰都写成子类。
改进版本
1
2
3
4
5
6
7
8
9
10
11
12public class Person { private String name; public Person(String name) { this.name = name; } public void show() { System.out.print("装扮的" + name); } }
1
2
3
4
5
6
7/** * 服饰 */ public abstract class Finery { public abstract void show(); }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37public class BigTrouser extends Finery { @Override public void show() { System.out.print("垮裤 "); } } public class LeatherShoes extends Finery { @Override public void show() { System.out.print("皮鞋 "); } } public class Sneakers extends Finery { @Override public void show() { System.out.print("破球鞋 "); } } public class Suit extends Finery { @Override public void show() { System.out.print("西装 "); } } public class Tie extends Finery{ @Override public void show() { System.out.print("领带 "); } } public class TShirts extends Finery { @Override public void show() { System.out.print("大T恤 "); } }
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27public class Client { public static void main(String[] args) { Person person = new Person("张无忌"); System.out.println("第一种装扮:"); Finery tShirts = new TShirts(); Finery bigTrouser = new BigTrouser(); Finery sneakers = new Sneakers(); tShirts.show(); bigTrouser.show(); sneakers.show(); person.show(); System.out.println(); System.out.println("第二种装扮:"); Finery suit = new Suit(); Finery tie = new Tie(); Finery leatherShoes = new LeatherShoes(); suit.show(); tie.show(); leatherShoes.show(); person.show(); } }
问题:虽然这里做到了服饰与人的分类,但只是一个一个列了出来,我们需要把所需的功能按正确的顺序串联起来进行控制。
这里不能使用建造者模式,因为建造者模式要求建造的过程必须是稳定的,而这个例子,建造过程是不稳定的。
装饰者模式
装饰模式,动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活。
Component
Component是定义一个对象接口,可以给这些对象动态地添加职责
1
2
3
4public abstract class Component { public abstract void operation(); }
Decorator
Decorator 装饰抽象类,继承了Component,从外类来扩展Component类的功能,但对于Component来说,是无需知道Decorator的存在的。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18public class Decorator extends Component { protected Component component; // 设置Component public void setComponent(Component component) { this.component = component; } // 重写operation(),实际执行的是Component的operation(); @Override public void operation() { if (component != null) { component.operation(); } } }
ConcreteComponent
ConcreteComponent定义了一个具体的对象,也可以给这个对象添加一些职责。
如果只有一个ConcreteComponent而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。
1
2
3
4
5
6
7
8
9public class ConcreteComponent extends Component{ @Override public void operation() { System.out.println("具体对象的操作"); } }
ConcreteDecorator
ConcreteDecorator就是具体的装饰对象,起到给Component添加职责的功能。
1
2
3
4
5
6
7
8
9
10
11
12
13
14public class ConcreteDecoratorA extends Decorator{ // 本类的独有功能,以区别于ConcreteDecoratorB private String addedState; @Override public void operation() { // 首先运行原Component的operation() super.operation(); // 再执行本类的功能,如addedState,相当于对原Component进行了装饰 addedState = "New State"; System.out.println("具体装饰对象A的操作"); } }
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17public class ConcreteDecoratorB extends Decorator { @Override public void operation() { // 首先运行原Component的operation() super.operation(); // 再执行本类的功能,如addedBehavior(),相当于对原Component进行了装饰 addedBehavior(); System.out.println("具体装饰对象B的操作"); } // 本类的独有方法,以区别于ConcreteDecoratorA private void addedBehavior() { } }
客户端
装饰模式是利用setComponent()来对对象进行包装的。这样每个装饰对象的实现就和如何使用这个对象分离开了,每个装饰对象只关心自己的功能,不需要关心如何被添加到对象链当中。
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15public class Client { public static void main(String[] args) { // 装饰的方法是:首先用ConcreteComponent实例化对象c ConcreteComponent c = new ConcreteComponent(); ConcreteDecoratorA d1 = new ConcreteDecoratorA(); ConcreteDecoratorB d2 = new ConcreteDecoratorB(); // 然后用ConcreteDecoratorA的实例化对象d1来包装c d1.setComponent(c); d2.setComponent(d1); // 再用ConcreteDecoratorB的对象d2包装d1,最终执行d2的operation(); d2.operation(); } }
简单总结:装饰者Decorator继承了Component,调用具体的装饰者的operation方法时,会先调用Component的operation方法,然后再调用装饰者自身添加的功能。
装饰者模式案例改进
Person(被装饰者)
这里Person就是具体的ConcreteComponent,没有Component,Decorator继承Person这个ConcreteComponent就可以。
1
2
3
4
5
6
7
8
9
10
11
12public class Person { private String name; public Person() {} public Person(String name) { this.name = name; } public void show() { System.out.print("装扮的" + name); } }
Finery(服饰类,装饰者)
装饰者继承具体的被装饰者,增强show()
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19/** * 服饰类(Decorator) */ public class Finery extends Person { protected Person component; // 打扮 public void decorate(Person component) { this.component = component; } public void show() { if(component!=null) { component.show(); } } }
具体服饰类
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46/** * 具体服饰类 */ public class TShirts extends Finery { @Override public void show() { System.out.print("大T恤 "); super.show(); } } public class BigTrouser extends Finery { @Override public void show() { System.out.print("垮裤 "); super.show(); } } public class LeatherShoes extends Finery { @Override public void show() { System.out.print("皮鞋 "); super.show(); } } public class Sneakers extends Finery { @Override public void show() { System.out.print("破球鞋 "); super.show(); } } public class Suit extends Finery { @Override public void show() { System.out.print("西装 "); super.show(); } } public class Tie extends Finery { @Override public void show() { System.out.print("领带 "); super.show(); } }
客户端
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26public class Client { public static void main(String[] args) { Person person = new Person("张无忌"); System.out.println("第一种装扮:"); Finery sneakers = new Sneakers(); Finery bigTrouser = new BigTrouser(); Finery tShirts = new TShirts(); sneakers.decorate(person); bigTrouser.decorate(sneakers); tShirts.decorate(bigTrouser); tShirts.show(); System.out.println(); System.out.println("第二种装扮:"); Finery leatherShoes = new LeatherShoes(); Finery tie = new Tie(); Finery suit = new Suit(); leatherShoes.decorate(person); tie.decorate(leatherShoes); suit.decorate(tie); suit.show(); } }
装饰者模式总结
装饰模式是为已有功能动态地添加更多功能的一种方式。
当系统需要新功能的时候,需要向旧的类中添加新的代码。这些新加的代码通常装饰了原有类的核心职责或主要行为。但问题在于在主类中加入了新的字段,新的方法和新的逻辑,从而增加了主类的复杂度。而这些新加入的东西仅仅是为了满足一些只在某种特定情况下才会执行的特殊行为的需要。
而装饰模式却提供了一个非常好的解决方案,它把每个要装饰的功能放在单独的类中,并让这个类包装它所要装饰的对象,因此,当需要执行特殊行为时,客户代码就可以在运行时根据需要有选择地、按顺序地使用装饰功能包装对象了。
装饰模式的优点:把类中的装饰功能从类中搬移去除,这样可以简化原有的类。可以有效地把类的核心职责和装饰功能区分开了。而且可以去除相关类中重复的装饰逻辑。
注:本文内容源自程杰的《大话设计模式》
最后
以上就是精明冬日最近收集整理的关于大话设计模式——装饰者模式的全部内容,更多相关大话设计模式——装饰者模式内容请搜索靠谱客的其他文章。
发表评论 取消回复