7 结构型模式之 - 装饰模式
九路 421 11

装饰模式介绍

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

装饰模式的定义

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

装饰模式的使用场景

需要透明且动态地扩展类的功能时

我们通过一个生活中的例子来介绍装饰模式的使用

人总是要穿衣服的,我们将人定义为一个抽象类,将其穿衣的行为定义为一个抽象方法。

 /**
  * 将人穿衣服定义成一个抽象方法
  */
 public abstract class Person {
     public abstract void dressed();
 }

该类也是我们要装饰的原始对象,那么具体装饰对象是谁呢?

我们要实现一个具体的实现类

/**
 * 具体装饰对象的实现类
 */
public class Boy extends Person{
    @Override
    public void dressed() {
        System.out.println("穿了内衣和内裤");
    }
}

Boy类继承于Person类,该类仅对Person中的dressed方法作了具体的实现,而Boy类则是我们所要装饰的具体对象,现在需要一个装饰者来装饰我们的这个Boy对象,这里定义一个PersonCloth类来表示人所穿着的衣服。

/**
 * 装饰者
 */
public abstract class PersonCloth extends Person{
    protected Person mPerson;

    public PersonCloth(Person person){
        mPerson = person;
    }

    @Override
    public void dressed() {
        mPerson.dressed();
    }
}

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

/**
 * 高档衣服
 */
public class ExpensiveCloth extends PersonCloth{
    public ExpensiveCloth(Person person) {
        super(person);
    }

    //穿了短袖
    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 person) {
        super(person);
    }

    //穿短裤
    public void dressShorts(){
        System.out.println("穿了短裤");
    }

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

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

/**
 * 测试类
 */
public class DecoratorTest {

    public static void main(String[] args){
        test();
    }

    public static void test(){

        //首先我们要有一个Person对象
        Person person = new Boy();

        //然后为他穿上便宜的衣服
        PersonCloth personCloth = new CheapCloth(person);
        person.dressed();

        //然后为他穿上了贵的衣服
        PersonCloth personCloth1 = new ExpensiveCloth(personCloth);
        personCloth1.dressed();
    }
}

运行结果如下:

穿了内衣和内裤
穿了内衣和内裤
穿了短裤
穿了短袖
穿了皮衣
穿了牛仔裤

评论区

索引目录