zoukankan      html  css  js  c++  java
  • 「补课」进行时:设计模式(10)——小明起床记了解装饰模式

    1. 前文汇总

    「补课」进行时:设计模式系列

    2. 小明起床记

    小明每天早晨都是起床困难大户,大冬天的太冷了,温暖的被窝紧紧的拉住小明,阻止小明每天早晨的起床。

    闹钟响了一遍又一遍,如果再不起床就要迟到了,迟到了就要扣钱,扣了钱就要喝西北风了。

    每天早晨督促小明起床的根本不是闹钟,而是贫穷。

    起床第一件事儿是穿衣服,先传衣服,再传裤子,然后穿鞋子,最后穿上一件外套,出门上班。

    首先,定义一个抽象的小明,小明是个人,所以定义一个人:

    public abstract class Person {
        abstract void dress();
    }
    

    每个人早晨起床都要穿衣服,这里定义一个穿衣服的方法。

    具体的小明上线:

    public class Man extends Person {
        @Override
        void dress() {
            System.out.println("先穿衣服");
        }
    }
    

    接下来我们要定义一个抽象的装饰器了,小明要穿的是衣服,我们将衣服抽象成一个类:

    public abstract class Clothes extends Person {
        private Person person;
    
        public Clothes(Person person) {
            this.person = person;
        }
    
        @Override
        void dress() {
            this.person.dress();
        }
    }
    

    接下来是具体的衣服:

    public class Trousers extends Clothes {
        public Trousers(Person person) {
            super(person);
        }
    
        @Override
        void dress() {
            super.dress();
            this.dressTrousers();
        }
    
        private void dressTrousers() {
            System.out.println("穿上裤子啦!!!");
        }
    }
    
    public class Shoes extends Clothes {
        public Shoes(Person person) {
            super(person);
        }
        @Override
        void dress() {
            super.dress();
            this.dressShoes();
        }
    
        private void dressShoes() {
            System.out.println("穿上鞋子啦!!!");
        }
    }
    
    public class Coat extends Clothes {
        public Coat(Person person) {
            super(person);
        }
    
        @Override
        void dress() {
            super.dress();
            this.dressCoat();
        }
    
        private void dressCoat() {
            System.out.println("穿上外套啦!!!");
        }
    }
    

    最后是一个测试类:

    public class Test1 {
        public static void main(String[] args) {
            Person person = new Man();
            person.dress();
    
            System.out.println("--------------");
            System.out.println("增加裤子适配器");
            person = new Trousers(person);
            person.dress();
    
            System.out.println("--------------");
            System.out.println("增加鞋子适配器");
            person = new Shoes(person);
            person.dress();
    
            System.out.println("--------------");
            System.out.println("增加外套适配器");
            person = new Coat(person);
            person.dress();
        }
    }
    

    测试结果如下:

    先穿衣服
    --------------
    增加裤子适配器
    先穿衣服
    穿上裤子啦!!!
    --------------
    增加鞋子适配器
    先穿衣服
    穿上裤子啦!!!
    穿上鞋子啦!!!
    --------------
    增加外套适配器
    先穿衣服
    穿上裤子啦!!!
    穿上鞋子啦!!!
    穿上外套啦!!!
    

    上面这么写有点麻烦,我们可以稍微缩减一下测试类,使用装饰器嵌套,一次性直接把所有的衣服都穿好:

    public class Test2 {
        public static void main(String[] args) {
            Person person = new Coat(new Shoes(new Trousers(new Man())));
            person.dress();
        }
    }
    

    3. 装饰器模式

    3.1 定义

    装饰模式(Decorator Pattern)是一种比较常见的模式,其定义如下:

    Attachadditional responsibilities to an object dynamically keeping the sameinterface.Decorators provide a flexible alternative to subclassing forextending functionality.(动态地给一个对象添加一些额外的职责。就增加功能来说,装饰模式相比生成子类更为灵活。)

    • Component: 抽象构件,是一个接口或者是抽象类,就是定义我们最核心的对象,也就是最原始的对象。
    • ConcreteComponent: 具体构件,是最核心、最原始、最基本的接口或抽象类的实现。
    • Decorator: 通用的装饰 ConcreteComponent 的装饰器,其内部必然有一个属性指向 Component 抽象组件;其实现一般是一个抽象类,主要是为了让其子类按照其构造形式传入一个 Component 抽象组件,这是强制的通用行为(当然,如果系统中装饰逻辑单一,并不需要实现许多装饰器,那么我们可以直接省略该类,而直接实现一个 具体装饰器(ConcreteDecorator) 即可)。
    • ConcreteDecorator: Decorator 的具体实现类,理论上,每个 ConcreteDecorator 都扩展了 Component 对象的一种功能。

    通用代码:

    public abstract class Component {
        abstract void operate();
    }
    
    public class ConcreteComponent extends Component {
        @Override
        void operate() {
            System.out.println("do Something");
        }
    }
    
    public abstract class Decorator extends Component {
        private Component component = null;
        // 通过构造函数传递被修饰者
        public Decorator(Component component) {
            this.component = component;
        }
        // 委托给被修饰者执行
        @Override
        void operate() {
            this.component.operate();
        }
    }
    
    public class ConcreteDecorator1 extends Decorator {
        // 定义被修饰者
        public ConcreteDecorator1(Component component) {
            super(component);
        }
        private void method1() {
            System.out.println("method1 修饰");
        }
    
        @Override
        void operate() {
            this.method1();
            super.operate();
        }
    }
    
    public class ConcreteDecorator2 extends Decorator {
        public ConcreteDecorator2(Component component) {
            super(component);
        }
        private void method2() {
            System.out.println("method2 修饰");
        }
    
        @Override
        void operate() {
            super.operate();
            this.method2();
        }
    }
    
    public class Test {
        public static void main(String[] args) {
            Component component = new ConcreteComponent();
            // 第一次修饰
            component = new ConcreteDecorator1(component);
            // 第二次修饰
            component = new ConcreteDecorator2(component);
            // 修饰后运行
            component.operate();
        }
    }
    

    3.2 优点

    装饰类和被装饰类可以独立发展,而不会相互耦合。换句话说, Component 类无须知道 Decorator 类, Decorator 类是从外部来扩展 Component 类的功能,而 Decorator 也不用知道具体的构件。

    3.3 缺点

    对于装饰模式记住一点就足够了:多层的装饰是比较复杂的。为什么会复杂呢?想想看,就像剥洋葱一样,至于剥到了最后才发现是最里层的装饰出现了问题,想象一下工作量吧,因此,尽量减少装饰类的数量,以便降低系统的复杂度。

    3.3 使用场景

    • 需要扩展一个类的功能,或给一个类增加附加功能。
    • 需要动态地给一个对象增加功能,这些功能可以再动态地撤销。
    • 需要为一批的兄弟类进行改装或加装功能,当然是首选装饰模式。
  • 相关阅读:
    spring-boot:run启动时,如何带设置环境参数dev,test.
    git多人参与的项目 -> 分支代码如何合并到主干
    如何使用IDEA运行 一个分布式的项目
    学习反射 并尝试写一个反射的工具类
    SVN提交大量无效文件补救方法
    IDEA基础配置
    Eclipse常用快捷键与IDEA中的对比.
    如何运行一个分布式的Maven项目
    Java常考面试题整理(六)
    python并发——多进程中的异常捕获
  • 原文地址:https://www.cnblogs.com/babycomeon/p/13983396.html
Copyright © 2011-2022 走看看