设计模式之--装饰模式

一、装饰模式的介绍
装饰模式(Decorator Pattern)也称为包装模式(Wrapper Pattern),结构型设计模式之一,其使用一种对客户端透明的方式来动态地扩展对象的功能,同时它也是继承关系的一种替代方案之一。在现实生活中也可以看见很多装饰模式的例子,或者可以大胆地说装饰模式无处不在,就拿人来说,人需要各式各样的衣着,不管你穿着怎样,但是,对于个人的本质来说是不变的,充其量只是在外面披上一层遮羞的物而已,这就是装饰模式,装饰物也许各不相同但是装饰的对象本质是不变的。

二、装饰模式的定义
动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生产子类更加为灵活。

三、装饰模式的使用场景
需要透明且动态地扩展类的功能时。

四、装饰模式的UML类图
这里写图片描述
根据UML类图可以得到出如下一个装饰模式的通用模式代码:

/**
 * 1、抽象组件类
 * @author chenyongliang
 */
public abstract class Component {
    /**
     * 抽象的方法,这个随你做 同样地你也可以增加更多的抽象方法
     */
    public abstract void operate();
}
/**
 * 2、组件的具体实现类
 * @author chenyongliang
 *
 */
public class ConcreteComponent extends Component {
    @Override
    public void operate() {
        // 具体逻辑,这个随你做
    }
}
/**
 * 3、抽象装饰者
 * @author chenyongliang
 */
public abstract class Decorator extends Component {
    private Component component;// 持有一个 Component 对象的引用
    /**
     * 必要的构造方法 需要一个 Component 类型的对象
     * 
     * @param component
     */
    public Decorator(Component component) {
        this.component = component;
    }

    @Override
    public void operate() {
        component.operate();
        System.out.println("===========Decorator---->operate===========");
    }
}
/**
 * 4、装饰者具体实现类
 * @author chenyongliang
 */
public class ConcreteDecoratorA extends Decorator {

    protected ConcreteDecoratorA(Component component) {
        super(component);
        //
    }

    @Override
    public void operate() {
        // 装饰方法A 和 B 既可以在父类方法前调用也可以在之后调用
        operateA();
        super.operate();
        System.out.println("=========ConcreteDecoratorA-->operate=========");
        operateB();
    }

    /**
     * 自定义的装饰方法B
     */
    private void operateB() {
        // 装饰方法逻辑
    }

    /**
     * 自定义的装饰方法A
     */
    private void operateA() {
        // 装饰方法逻辑
    }
}
/**
 * 5、客户调用类
 * @author chenyongliang
 *
 */
public class Client {
    public static void main(String[] args) {
        // 构造被装饰的组件对象
        Component component = new ConcreteComponent();
        // 根据组件对象构造装饰者对象A并调用,此时相当于给组件对象增加装饰者A的功能方法。
        Decorator decorator = new ConcreteDecoratorA(component);
        decorator.operate();
    }
}

角色介绍:
(1)Component: 抽象组件。可以是一个接口或抽象类,其充当的就是被装饰的原始对象。
(2)ConcreteComponent: 组件具体实现类。该类是Component 类的基本实现,也是我们装饰的具体对象。
(3)Decorator: 抽象装饰者。其承担的职责就是为了装饰我们的组件对象,其内部一定要有一个指向组件对象的引用。在大多数情况下,该类为抽象类,需要根据不同的装饰逻辑实现不同的具体子类。当然,如果装饰逻辑单一,只有一个情况下我们可以省略该类直接作为具体的装饰者。
(4)ConcreteDecoratorA: 装饰者具体实现类。只是对抽象装饰者做出具体的实现。
(5)ConcreteDecoratorB: 同上。
(6)Client: 客户类。

五、装饰模式的简单实现
我们以人穿衣服为例子,将人定义为一个抽象类,将其穿衣的行为定义为一个抽象方法。

public abstract class Person {
    /**
     * Person 下有一个穿着的抽象方法
     */
    public abstract void dressed();
}

该类其实就是上面我们所提及的抽象组件类,也就是我们需要装饰的原始对象,那么具体装饰谁呢?我们需要一个具体的实现类。

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

Boy 类继承于 Person 类,该类仅对 Person 中的 dressed 方法作了具体的实现,而 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 类的引用,可以方便地调用具体被装饰对象中的方法,这也是为什么我们可以在不破坏原类层次结构的情况下为类增加一些功能,我们只需要在被装饰对象的相应方法前或后增加相应的功能逻辑即可。在装饰物只有一个的情况下,可不必声明一个抽象类作为装饰者抽象的提取,仅需定义一个普通的类表示装饰者即可,这里为了表明示例我们定义两种衣服类型,一个类 ExpensiveCloth 表示高档衣服。

public class ExpensiveCloth extends PersonCloth {

    public ExpensiveCloth(Person mPerson) {
        super(mPerson);
    }
    /**
     * 穿短袖
     */
    private void dressShirt(){ 
        System.out.println("穿件短袖");
    }

    /**
     * 穿皮衣
     */
    private void dressLeather(){ 
        System.out.println("穿件皮衣");
    }
    /**
     * 穿牛仔裤
     */
    private void dressJean(){ 
        System.out.println("穿件牛仔裤");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressShirt();
        dressLeather();
        dressJean();
    }

}

而另一个类 CheapCloth 则表示便宜的衣服。

public class CheapCloth extends PersonCloth {

    public CheapCloth(Person mPerson) {
        super(mPerson);
    }

    /**
     * 穿短袖
     */
    public void dressShorts() {
        System.out.println("穿件短袖");
    }

    @Override
    public void dressed() {
        super.dressed();
        dressShorts();
    }

}

这两个类本质上并没有区别,两者都是为原本 Boy 类中的 dressed 方法提供功能扩展,不过这种扩展并非是直接修改原有的方法逻辑或结构,更恰当地说,仅仅是在另一个类中将原有方法和新逻辑进行封装整合而已。最后我们来看看客户类中的调用。

public class Main {
    public static void main(String[] args) {
        // 首先我们要有一个 Person 男孩
        Person person = new Boy();

        //然后给他穿上便宜的衣服
        PersonCloth clothCheap = new CheapCloth(person);
        clothCheap.dressed();
        System.out.println("=========================================");
        //然后给他穿上比较上档次的衣服
        PersonCloth clothExpensive = new ExpensiveCloth(person);
        clothExpensive.dressed();
    }
}

六、总结
装饰模式和代理模式有点类似,有时甚至容易混淆,倒不是说会把代理当成装饰,而常常会是讲装饰看作代理,所以大家一定要多留心,装饰模式是以客户端透明的方式扩展对象的功能,是继承关系的一个替代方案;而代理模式则是给一个对象提供一个代理对象,并有代理对象来控制对原有对象的引用。装饰模式应该为所装饰的对象增强功能;代理模式对代理的对象施加控制,但不对对象本身的功能进行增强。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值