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流中也是应用了装饰器模式。

原文地址:https://www.cnblogs.com/1925yiyi/p/9209537.html