Java设计模式07:常用设计模式之装饰器模式(结构型模式)

1. Java之装饰器模式(Decorator Pattern)

(1)概述:

    装饰模式在Java种使用也很广泛,比如我们在重新定义按钮、对话框等时候,实际上已经在使用装饰模式了。在不必改变原类文件和使用继承的情况下,装饰模式使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案之一,它是通过创建一个包装对象,也就是装饰来包裹真实的对象

    装饰者模式:动态地给一个对象添加一些额外的职责,就像在墙上刷油漆一样。就增加功能来说,Decorator模式比生成子类更为灵活。

  Decorator模式的工作原理是:可以创建始于Decorator对象(负责新的功能的对象)终于原对象的一个对象"链"

                       

                        图1  装饰者链

装饰模式的特点

  • 装饰对象和真实对象有相同的接口。这样客户端对象就能以和真实对象相同的方式和装饰对象交互。
  • 装饰对象包含一个真实对象的引用(reference)
  • 装饰对象接受所有来自客户端的请求。它把这些请求转发给真实的对象。
  • 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

 

(2)装饰模式的UML类图:

抽象组件角色(Component):定义一个对象接口,以规范准备接受附加责任的对象,即可以给这些对象动态地添加职责。

具体组件角色(ConcreteComponent) 被装饰者,定义一个将要被装饰增加功能的类。可以给这个类的对象添加一些职责

抽象装饰器(Decorator):维持一个指向构件Component对象的实例,并定义一个与抽象组件角色Component接口一致的接口

具体装饰器角色(ConcreteDecorator):向组件添加职责。

 

(3)下面是装饰者模式通用模式代码

  1 /******************抽象组件类**************/
  2 public abstract class Component {
  3     /**
  4     * 抽象的方法,这个随你做
  5     * 同样第你也可以增加更多的抽象方法
  6     */
  7     public abstract void operate();
  8 }
  9 
 10 
 11 /******************组件具体实现类**************/
 12 public class ConcreteComponent extends Component {
 13     @Override
 14     public void operate() {
 15         //具体逻辑,这个随你做
 16     }
 17 }
 18 
 19 
 20 /******************抽象装饰者**************/
 21 public abstract class Decorator extends Component {
 22     private Component component;//持有一个Component对象的引用
 23     /*
 24     *必要的构造方法 需要一个Component类型的对象
 25     *
 26     * @param component Component对象
 27     */
 28     public Decorator(Component component) {
 29         this.component = component;
 30     }
 31     
 32     @Override
 33     public void operate() {
 34         component.operate();
 35     }
 36     
 37 }
 38 
 39 
 40 /******************装饰者具体实现类A**************/
 41 public class ConcreteDecoratorA extends Decorator {
 42     protected ConcreteDecoratorA(Component component) {
 43         super(component);
 44     }
 45     
 46     @Override
 47     public void operate() {
 48         //装饰方法A和B既可在父类方法前调用也可在之后调用
 49         operateA();
 50         
 51         super.operate();
 52         
 53         operateB();
 54     }
 55     
 56     /**
 57     * 自定义的装饰方法A
 58     */
 59     public void operateA() {
 60         //装饰方法的逻辑
 61     }
 62     
 63     /**
 64     * 自定义的装饰方法B
 65     */
 66     public void operateB() {
 67         //装饰方法的逻辑
 68     }
 69 }
 70 
 71 /******************装饰者具体实现类B**************/
 72 public class ConcreteDecoratorB extends Decorator {
 73     
 74     protected ConcreteDecoratorB(Component component) {
 75         super(component);
 76     }
 77     
 78     @Override
 79     public void operate() {
 80         //装饰方法A和B既可在父类方法前调用也可在之后调用
 81         operateA();
 82         
 83         super.operate();
 84         
 85         operateB();
 86     }
 87     
 88     /**
 89     * 自定义的装饰方法A
 90     */
 91     public void operateA() {
 92         //装饰方法的逻辑
 93     }
 94     
 95     /**
 96     * 自定义的装饰方法B
 97     */
 98     public void operateB() {
 99         //装饰方法的逻辑
100     }
101 }
102 
103 
104 /******************客户调用类**************/
105 public class Client {
106     public static void main(String[] args) {
107         //构建被装饰的组件对象
108         Component component = new Component();
109         
110         //根据组件对象构建装饰者对象A并调用,此时相当于给组件对象增加装饰者A的功能方法
111         Decorator decorator = new ConcreteDecoratorA(component);
112         decorator.operate();
113         
114         //根据组件对象构建装饰者对象B并调用,此时相当于给组件对象增加装饰者B的功能方法
115         Decorator decoratorB = new ConcreteDecoratorB(component);
116         decoratorB.operate();
117     }
118 }

 

 

 

2. 装饰器模式简单实现:

人需要各式各样的衣着,不管你穿着怎么样,但是,对于个人的本质来说是不可变的,充其量只是在外面披上一层遮羞物。

(1)人总是需要穿衣服的,我们这里将人定义一个抽象类,将穿衣的行为定义一个抽象方法:

抽象组件类

1 public abstract class Person {
2     /**
3     * Person 下有一个穿着的抽象方法
4     */
5     
6     public abstract void dressed();
7 }

 

(2)接下来我们需要具体装饰谁呢? 也就是说我们需要创建一个具体组件类,如下:

具体组件类

1 public class Boy extends Person {
2     
3     @Override
4     public void dressed() {
5         //Boy 类下dressed方法的基本逻辑
6         System.out.println("穿了内衣内裤");
7     }
8 }

 

 

(3)上面的Boy类就是我们所要装饰的具体对象,现在需要一个装饰者来装饰我们的这个Boy对象,这里定义一个PersonCloth类来表示人所穿着的衣服

抽象装饰者类

public abstract class PersonCloth extends Person {
    protected Person mPerson;//保持一个Person类的引用
    
    public PersonCloth(Person mPerson) {
        this.mPerson = mPerson;
    }
    
    @Override
    public void dressed() {
        //调用Person类中的dressed方法
        
        mPerson.dressed();
    }
}

在PersonCloth类中我们保持一个对Person的引用,这样就可以方便地调用具体被装饰对象中的方法,这也是为什么我们可以在不破坏原类层次结构的情况下为类增加一些功能,我们只需要在被装饰对象的相应方法前 或者 后 增加相应的功能逻辑即可。

 

(4)定义两种装饰具体实现类,如下:

装饰具体实现类之 高档衣服

 1 public class ExpensiveCloth extends PersonCloth {
 2     public ExpensiveCloth(Person person) {
 3         super(person);
 4     }
 5     
 6     
 7     
 8     //穿短袖
 9     private void dressShirt() {
10         System.out.println("穿件短袖");
11     }
12     
13     //穿皮衣
14     private void dressLeather(){
15         System.out.println("穿件皮衣");
16     }
17     
18     //穿牛仔裤
19     private void dressJean(){
20         System.out.println("穿牛仔裤");
21     }
22     
23     
24     @Override
25     public void dressed() {
26         super.dressed();
27         
28         dressShirt();
29         dressLeather();
30         dressJean();
31     }
32     
33 }

装饰具体实现类之 便宜的衣服

 1 public class CheapCloth extends PersonCloth {
 2     
 3     public CheapCloth(Person mPerson) {
 4         super(mPerson);
 5     }
 6     
 7     
 8     //穿短袖
 9     private void dressShorts() {
10         System.out.println("穿件短袖");
11     }
12     
13     
14     @Override
15     public void dressed() {
16         super.dressed();
17         
18         dressShorts();
19     }
20 }

 

 

(5)客户端类:

 1 public class Main {
 2     
 3     public static void main(String[] args) {
 4         //首先我们要有一个Person男孩
 5         Person person = new Boy();
 6         
 7         //然后为他穿上便宜的衣服,比如爱哥这样的Boy
 8         PersonCloth clothCheap = new CheapCloth(person);
 9         clothCheap.dressed();
10         
11         //或者给他穿上比较上档次的衣服,如SM
12         PersonCloth clothExpensive = new ExpensiveCloth(person);
13         clothExpensive.dressed();
14     }
15     
16 }

 

posted on 2015-10-13 10:04  鸿钧老祖  阅读(183)  评论(0编辑  收藏  举报

导航