• 装饰模式


    装饰模式(Decotator),动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生产子类更为灵活。
    说白了,这个ConcreteComponent具体对象,就是我们最终需要的。我们可以通过Decorator来丰富ConcreteComponent具体对象,也就是给它添加一些职责,但这个职责的顺序是可以变化的(个人感觉这也是跟建造者模式的最大区别,不然这两个设计模式还是有点像)

    大话设计模式里有这么一句话感觉特别好,学习设计模式要善于变通,如果只有一个ConcreteComponent类而没有抽象的Component类,那么Decorator类可以是ConcreteComponent的一个子类。同样道理,如果只有一个ConcreteDecorator类,那么就没有必要建立一个单独的Decorator类,而可以把Decorator和ConcreteDecorator的责任合并成一个类。

    装饰模式主要是为了有效地把类的核心职责和装饰功能区分开,因为我们有了Decorator装饰抽象类,可以从外部类来扩展功能。

    我们以动物行为来写个例子:
    我们知道动物都有技能(吃,喝,睡觉),我们现在有这么一个具体的狗对象类,那么我们在给狗丰富技能时,如何让丰富技能这个操作分离出去?这个时候就可以用到装饰模式了。

    1.一个抽象的Animal动物类,拥有一个技能抽象方法。
    考虑下为什么这里不用接口?这是因为如果用接口的话,下面的装饰类就不能运用多态特性。
    /**
    * 抽象动物基类,动物一些基本技能
    * @author lizhibiao
    * @date 2019/2/1 15:38
    */
    public abstract class Animal
    {
    /**
    * 动物技能抽象方法
    */
    public abstract void skill();

    }


    2.一个具体动物对象类,这里是狗(当然我们还可以继续增加猫类,鸟类。。。)
    让狗对象类继承抽象的动物类,并实现skill()方法。
    /**
    * 具体的狗对象,实现抽象父类
    * @author lizhibiao
    * @date 2019/2/1 15:22
    */
    public class Dog extends Animal
    {
    @Override
    public void skill()
    {
    System.out.println("动物都会跑");
    }
    }


    3.增加一个抽象的技能装饰类,这个类最主要是通过传入具体对象类(例如:狗),实现抽象的skill()方法,调用具体对象的技能方法。
    /**
    * 抽象的技能装饰类
    * 注意这里一定要重新抽象类的抽象方法
    * @author lizhibiao
    * @date 2019/2/1 15:31
    */
    public abstract class DecoratorBehavior extends Animal
    {

    private Animal animal;

    /**
    * 普通的实例化方法,这里传入的是Animal的子类,也就是具体对象
    * @param animal animal
    */
    public void setAnimal(Animal animal)
    {
    //多态,Animal指向子类的实例
    //为什么可以多态,因为继承关系可以向上转型,也就是子类可以向上转型成父类,除了能够引用父类的共性外,还可以使用子类强大的功能。
    this.animal = animal;
    }

    /**
    * 重新实现技能方法,这里是调用具体对象的方法(例如,当前是狗类,那么调用的是狗类的“动物都会跑”)
    */
    @Override
    public void skill()
    {
    if (null != animal)
    {
    //这里调用的是具体对象的skill()方法
    //例如,当前的animal是狗类,那么调用的是狗的skill
    //例如,当前的animal是猫类,那么调用的是猫的skill
    animal.skill();
    }
    }
    }

    4.我们要给狗添加警戒和睡觉的功能,于是添加两个技能类
    继承自DecoratorBehavior,实现skill方法,并先调用父类方法,然后调用自己特有方法
    /**
    * 狗的看家技能
    * @author lizhibiao
    * @date 2019/2/1 15:53
    */
    public class Guard extends DecoratorBehavior
    {

    @Override
    public void skill()
    {
    //先实现父类的方法
    super.skill();
    canGuard();
    }

    private void canGuard()
    {
    System.out.println("狗还会看家");
    }

    }
    /**
    * 睡觉技能
    * @author lizhibiao
    * @date 2019/2/1 16:39
    */
    public class Sleep extends DecoratorBehavior
    {
    @Override
    public void skill()
    {
    //实现父类的所有技能
    super.skill();
    sleep();
    }

    /**
    * 睡觉方法
    */
    private void sleep()
    {
    System.out.println("睡觉真是件舒服的事情!");
    }
    }


    5.客户端测试类
    /**
    * 客户端测试类
    * @author lizhibiao
    * @date 2019/2/1 16:17
    */
    public class Client
    {
    public static void main(String[] args)
    {
    //先new一个具体狗对象类
    Dog dog = new Dog();
    //new一个警戒技能
    Guard guard = new Guard();
    //子类狗调用父类DecoratorBehavior的setAnimal()方法,将狗对象类传入,多态
    //此时的DecoratorBehavior的成员属性Animal已经是子类狗对象类
    guard.setAnimal(dog);
    //new一个睡觉技能
    Sleep sleep = new Sleep();
    //将警戒对象传入父类DecoratorBehavior的setAnimal()方法
    //此时的DecoratorBehavior的成员属性Animal已经变成警戒对象
    sleep.setAnimal(guard);

    //按照Dog的skill()方法--->Guard的canGuard()方法--->sleep的sleep()顺序执行
    sleep.skill();

    }
    }

    这里的执行顺序比较难理解,我们来理理思路,执行到下面代码:
    sleep.setAnimal(guard)
    sleep.skill()
    到这里了其实当前的类成员属性Animal已经是Guard警戒对象类了

    所以sleep.skill(),这里会先调用警戒类Guard的skill()方法,再调用sleep()睡觉方法
    /**
    * 睡觉技能
    * @author lizhibiao
    * @date 2019/2/1 16:39
    */
    public class Sleep extends DecoratorBehavior
    {
    @Override
    public void skill()
    {
    //实现父类的所有技能
    super.skill();
    sleep();
    }


    而警戒类又会先去调用Dog的skill()方法“动物都会跑”,再去调用警戒方法canGuard()
    /**
    * 狗的看家技能
    * @author lizhibiao
    * @date 2019/2/1 15:53
    */
    public class Guard extends DecoratorBehavior
    {

    @Override
    public void skill()
    {
    //先实现父类的方法
    super.skill();
    canGuard();
    }


    所以打印的顺序结果如下:
    动物都会跑
    狗还会看家
    睡觉真是件舒服的事情!



    最后总结下:
    我们可以看出,装饰模式虽然将技能的丰富给分离出去了,但是我们发现,每次增加一个技能时都需要增加一个小类(例如:我要再给增加会啃骨头、会找到回家的路。。。就需要再增加类),这样会产生很多小对象。
  • 相关阅读:
    InnoDB和MyISAM区别
    include和require的区别
    php的魔术方法
    php中heredoc的使用方法
    20条常见的编码陷阱
    php header 跳转
    php.ini设置详解
    session的实现原理 大网站应用应注意的问题
    Ruby on Rails 开发实践相关命令参考
    IBM WebSphere Portal6 最佳项目实践
  • 原文地址:https://www.cnblogs.com/lizb0907/p/10346563.html
Copyright © 2020-2023  润新知