zoukankan      html  css  js  c++  java
  • java进阶系列之装饰器模式

    1、介绍

    装饰器模式顾名思义就是装饰某个对象的,是一种结构型模式。装饰器模式允许向一个现有对象添加新的功能,同时不改变其结构,用户可以随意的扩展原有的对象。它是作为现有的类的一个包装。装饰器模式一方面替代了继承,相对于继承带来的静态的功能扩展,装饰器模式可以理解为动态的功能扩展,非常灵活。但是由于动态扩展带来方便的同时也带来了缺点:在装饰过程中,其实创建了很多的对象占据内存资源,这些对象都很相似,排查错误也是有很大困难。

    举例来说:比如有一根电线,现在只有铜丝,只不过现在只能导电,我们在他的外面加一层绝缘体比如橡胶,这样他在导电的同时还安全了,外部具有绝缘的功能。

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

    主要解决:一般的我们为了扩展一个类经常使用继承方式实现,由于继承为类引入静态特征,并且随着扩展功能的增多,子类也会很膨胀。

    何时使用:在不想增加很多子类的情况下扩展类。

    如何解决:将具体功能职责划分,同时继承装饰者模式。

    应用场景:1、扩展一个类的功能;2、动态增加功能,动态撤销。

    实例:装饰器模式中有一个抽象的对象,定义为接口。为何这么定义呢?这里的例子是电脑的例子,先定义一个基本的电脑,它可以是笔记本电脑,台式电脑,平板电脑等等,但是它们都有一个相同的基本信息,它们有名字,有价格。我们定义所有电脑基本的抽象方法,后期如果有新式电脑出现,新的名字,新的价格出现,最基本的是这些。

    步骤1

    创建一个接口。

    package demo_dectorator;  
      
    public interface AbstractComputer {  
        abstract String name();  //电脑名字
      
        abstract double price();  //电脑价格
    }

    步骤2

    创建实现接口的实体类

    下面是一个对接口的实现,也是对抽象产品的具体化,这个实现可能会有很多,因为有很多品牌名字价格的电脑,这也是为何定义一个抽象类或接口的原因。假设电脑的基本价格是3000,名字是普通电脑。

    package demo_dectorator;  
      
    public class Computer implements AbstractComputer{  
      
        @Override  
        public String name() {  
            return "普通电脑";  
        }  
      
        @Override  
        public double price() {  
            return 3000;  
        }  
      
    }

    步骤3

    创建实现了AbstractComputer接口的抽象装饰类

    下面我们对这个电脑进行改进,我们要在电脑里加内存条,增大运行内存,定义一个抽象的原件类,同样实现接口,为什么这样呢?

    装饰者模式必然有一个公共的接口或者抽象类,用来作为对象的传递。你需要根据接口实现基本的被装饰类,以及装饰类的公共接口,以后所有的装饰类都是继承自公共的装饰类接口,内部实现。

    在逻辑上也是可以说的过去的,电脑配件依附于电脑,拥有和电脑一样的属性。

    package demo_dectorator;  
      
    public abstract class Device implements AbstractComputer{  
      
        public abstract String name();  
      
        public abstract double price();  
    }  

    步骤4

    创建扩展了Device类的实体装饰类

    package demo_dectorator;  
      
    /*内存类*/  
      
    public class Memory extends Device{  
      
        public AbstractComputer computer;  
      
        public Memory(AbstractComputer computer) {  
            this.computer = computer;  
        }  
      
        public String name() {  
            return computer.name() + "加内存";  
        }  
      
        public double price() {  
            return computer.price() + 300;  
        }  
      
    }  
    package demo_dectorator;  
      
    /*硬盘类*/  
      
    public class HardDisk extends Device{  
        public AbstractComputer computer;  
      
        public HardDisk(AbstractComputer computer) {  
            this.computer = computer;  
        }  
      
        public String name() {  
            return computer.name() + "加硬盘";  
        }  
      
        public double price() {  
            return computer.price() + 500;  
        }  
    }

    在装饰的过程中最重要的就是子类继承父类,在执行子类的构造方法的时候,会隐式调用super(),如下

    public Memory(AbstractComputer computer) {  
            super();  
            this.computer = computer;  
        }
    public HardDisk(AbstractComputer computer) {  
            super();  
            this.computer = computer;  
        } 

    步骤5

    使用 HardDisk、Memory来装饰 AbstractComputer对象。

    package demo_dectorator;  
      
    /* 
    * 客户类,测试装饰器模式*/  
      
    public class Client {  
        public static void main(String[] args) {  
      
            Computer computer = new Computer();  
      
            HardDisk h = new HardDisk(computer);
            System.out.println(h.name());  
            System.out.println("价格:"+h.price());  
      
            Memory m = new Memory(computer);  
            System.out.println(m.name());  
            System.out.println("价格:"+m.price());  
      
            HardDisk h1=new HardDisk(m);  
            System.out.println(h1.name());  
            System.out.println("价格:"+h1.price());  
      
      
        }  
    } 

    步骤6

    测试输出

    普通电脑加硬盘  
    价格:3500.0  
    普通电脑加内存  
    价格:3300.0  
    普通电脑加内存加硬盘  
    价格:3800.0 

    装饰器模式很好的体现开闭原则:对于扩展是开放的,对于修改是关闭的。用户可以动态添加功能。在java的io流中也是应用了装饰器模式。

  • 相关阅读:
    redis-client和redis-template存储的key的格式不一样
    dubbo+zookeeper基础
    java面试题1
    Spring线程池(异步、同步)
    Java并发多线程
    Java并发-并发工具类JUC
    Java并发面试题
    ActiveMQ
    一键部署springboot到Docker
    Quartz任务调度学习
  • 原文地址:https://www.cnblogs.com/1925yiyi/p/9209537.html
Copyright © 2011-2022 走看看