zoukankan      html  css  js  c++  java
  • Java中设计模式之装饰者模式-3

    装饰者模式:

    动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更加有弹性的替代方案。
    装饰者核心:实现功能组合

    继承与组合区别:

    继承
    继承是给一个类添加行为的比较有效的途径。通过使用继承,可以使得子类在拥有自身方法的同时,还可以拥有父类的方法。但是使用继承是静态的,在编译的时候就已经决定了子类的行为,我们不便于控制增加行为的方式和时机。

    组合
    组合即将一个对象嵌入到另一个对象中,由另一个对象来决定是否引用该对象来扩展自己的行为。这是一种动态的方式,我们可以在应用程序中动态的控制。

    与继承相比,组合关系的优势就在于不会破坏类的封装性,且具有较好的松耦合性,可以使系统更加容易维护。但是它的缺点就在于要创建比继承更多的对象。

    装饰者模式优点

    一句话:在原有的基础上 ,增加功能 ,提高效率

    1、装饰者模式可以提供比继承更多的灵活性

    2、可以通过一种动态的方式来扩展一个对象的功能,在运行时选择不同的装饰器,从而实现不同的行为。

    3、通过使用不同的具体装饰类以及这些装饰类的排列组合,可以创造出很多不同行为的组合。可以使用多个具体装饰类来装饰同一对象,得到功能更为强大的对象。

    4、具体构件类与具体装饰类可以独立变化,用户可以根据需要增加新的具体构件类和具体装饰类,在使用时再对其进行组合,原有代码无须改变,符合“开闭原则”。

    装饰者模式缺点

    一句话:繁琐

    1、会产生很多的小对象,增加了系统的复杂性

    2、这种比继承更加灵活机动的特性,也同时意味着装饰模式比继承更加易于出错,排错也很困难,对于多次装饰的对象,调试时寻找错误可能需要逐级排查,较为烦琐。

    装饰者应用场景

    1、在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

    2、需要动态地给一个对象增加功能,这些功能也可以动态地被撤销。 当不能采用继承的方式对系统进行扩充或者采用继承不利于系统扩展和维护时。

    个人理解:
    装饰者模式是指在继承父类后,重写父类方法时,不改变父类中该方法的原有功能,只是在该功能基础上添加自己想要扩充的功能。

    一句话:父类原有功能不变,子类再添加其他功能

    简单实例:

    父类

    package 设计模式之装饰者模式;
    
    public class Father {
        public void run(){
            System.out.println("跑步...");
        }
    }
    

    子类:
    在子类中重写run方法时,不改变父类的原有功能,并根据需要添加自己的功能。这里的装饰并不复杂,不存在多层装饰,所以在子类中创建一个父类属性是多余的,但在多层装饰中,这是必要的。

    package 设计模式之装饰者模式;
    
    public class Son extends Father {
        Father father;
    
        public Son(Father father) {
            super();
            this.father = father;
        }
    
        @Override
        public void run() {
            System.out.println("欣赏周围的美景...");
            father.run();
            System.out.println("听歌...");
        }
    }
    

    测试类:

    package 设计模式之装饰者模式;
    
    public class Test {
        public static void main(String[] args){
            Father father=new Father();
            father.run();
            System.out.println("son:");
            Son son = new Son(father);
            son.run();
        }
    }
    

    结果:

    这里写图片描述

    多层装饰实例

    借鉴实例,来自http://www.cnblogs.com/xinye/p/3910149.html
    逻辑分析图:
    这里写图片描述

    1.装饰者基类(被操作的对象)

    package com.xinye.test.decoration;
    /**
     * 食物基类
     * @author xinye
     *
     */
    public abstract class Food {
    
        protected String desc;
    
        public abstract String getDesc();
    }

    2.被操作对象具体类

    鸡肉

    package com.xinye.test.decoration;
    /**
     * 鸡肉
     * @author xinye
     *
     */
    public class Chicken extends Food {
        public Chicken(){
            desc = "鸡肉";
        }
        @Override
        public String getDesc() {
            return desc;
        }
    
    }

    鸭肉

    package com.xinye.test.decoration;
    /**
     * 鸭肉
     * @author xinye
     *
     */
    public class Duck extends Food {
        public Duck(){
            desc = "鸭肉";
        }
        @Override
        public String getDesc() {
            return desc;
        }
    
    }

    3.装饰者基类(操作类,对对象实现什么操作)

    package com.xinye.test.decoration;
    /**
     * 
     * @author xinye
     *
     */
    public abstract class FoodDecoration extends Food {
    
        @Override
        public abstract String getDesc();
    
    }

    4.具体操作类

    蒸-装饰者

    package com.xinye.test.decoration;
    /**
     * 蒸食物
     * @author xinye
     *
     */
    public class SteamedFood extends FoodDecoration {
    
        private Food food;
    
        public SteamedFood(Food f){
            this.food = f;
        }
    
        @Override
        public String getDesc() {
            return getDecoration() + food.getDesc();
        }
    
        private String getDecoration(){
            return "蒸";
        }
    }

    烤-装饰者

    package com.xinye.test.decoration;
    /**
     * 烤食物
     * @author xinye
     *
     */
    public class RoastFood extends FoodDecoration {
    
        private Food food;
    
        public RoastFood(Food f){
            this.food = f;
        }
    
        @Override
        public String getDesc() {
            return getDecoration() + food.getDesc();
        }
    
        private String getDecoration(){
            return "烤";
        }
    }

    5.测试类(客户端)

    package com.xinye.test.decoration;
    /**
     * 客户端
     * @author xinye
     *
     */
    public class Client {
        public static void main(String[] args) {
            // 测试单纯的食物
            Food f1 = new Chicken();
            System.out.println(f1.getDesc());
    
            System.out.println("----------------------");
            // 测试单重修饰的食物
            RoastFood rf = new RoastFood(f1);
            System.out.println(rf.getDesc());
    
            System.out.println("----------------------");
            // 测试多重修饰的食物
            SteamedFood sf = new SteamedFood(rf);
            System.out.println(sf.getDesc());
        }
    }

    执行结果:

    鸡肉
    烤鸡肉
    蒸烤鸡肉

  • 相关阅读:
    jboss服务器下的中文乱码问题
    rpm数据库被损坏修复方案
    python http post简单例子
    python 获取时间戳相关计算
    Qt 之Excel 操作(二 强化版本)
    SqlServer查询某重复列根据条件取一条数据
    查看各表所占空间
    Taro 1.3.x版本 编译时报错 UnhandledPromiseRejectionWarning: Error: ENOENT: no such file or directory, open 'util'
    React index.html引入script时 src中的斜杠都变成了空格,并且还多出了script标签 导致无法加载
    支付宝小程序 iOS报页面访问受限aboud:srcdoc android无此问题 2021记录
  • 原文地址:https://www.cnblogs.com/TCB-Java/p/6770127.html
Copyright © 2011-2022 走看看