• 装饰器模式


    1、概念:装饰模式是在不必改变原类文件和使用继承的情况下,动态的扩展一个对象的功能。它是通过创建一个包装对象,也就是装饰来包裹真实的对象,又叫做包装模式。

    2、在java的IO流这个章节中,我们会发现有底层流,比如说字节和字符流,有缓冲流等等:

    FileOutputStream:基本的文件输出流 BufferedOutputStream:缓冲流 DataOutputStream :输出二进制数据的缓冲流,这三种流我们可以随机组合而实现不同功能

    new BufferedOutputStream(new FileOutputStream):带有缓冲流的文件输出流

    new DataOutputStream(new FileOutputStream):带有输出二进制数据的文件输出流

    new DataOutputStream(new BufferedOutputStream(new FileOutputStream)):带有双层缓冲流的可以输出二进制数据的文件输出流

    这样组合就实现了各种不同的功能,在IO流中大量使用了我们的装饰模式

    3、装饰模式的角色:

    抽象组件角色(Component):给出一个抽象接口,以规范准备接收附加功能的对象

    具体组件角色(Concrete Component):定义一个将要接收附加功能的类

    装饰角色(Decorator):持有一个组件(Component)对象的引用,并定义一个与抽象组件接口一致的接口

    具体装饰角色(Concrete Decorator):负责给构件对象贴上附加的功能

    4、装饰模式特点:

    (1) 装饰对象和被装饰对象有相同的接口。这样客户端对象就可以以和被装饰对象相同的方式和装饰对象交互。
    (2) 装饰对象包含一个被装饰对象的索引(reference)
    (3) 装饰对象接受所有的来自客户端的请求。它把这些请求转发给被装饰的对象。
    (4) 装饰对象可以在转发这些请求以前或以后增加一些附加功能。这样就确保了在运行时,不用修改给定对象的结构就可以在外部增加附加的功能。在面向对象的设计中,通常是通过继承来实现对给定类的功能扩展。

    5、装饰模式与继承的区别:

    装饰模式 :用来扩展特定对象的功能 不需要子类 动态地 运行时分配职责 防止由于子类而导致的复杂和混乱 。对于一个给定的对象,同时可能有不同的装饰对象,客户端可以通过它的需要选择合适的装饰对象来进行装饰,对于所有可能的组合,很容易增加

    继承:用来扩展一类对象的功能 需要子类 静态地 编译时分派职 缺乏灵活性 导致很多子类产生。

    6、案例

    package com.model.decorator;
    
    /**
     * 抽象主题对象--饮料类
     * Created by Administrator on 2016/3/2.
     */
    public abstract class Berverage {
    	protected String description = "Unknow Berverage";
    
    	public String getDescription() {
    		return description;
    	}
    
    	public abstract double cost();
    }
    
    package com.model.decorator;
    
    /**
     * 具体的被装饰对者
     * Created by Administrator on 2016/3/2.
     */
    public class Espresso extends Berverage {
    
    	public Espresso(){
    		description = "Espresso";
    	}
    
    	@Override
    	public double cost() {
    		return 1.99;
    	}
    }
    
    package com.model.decorator;
    
    /**
     * 调味品装饰器,装饰器接口类
     * Created by Administrator on 2016/3/2.
     */
    public abstract class CondimentDecorator extends Berverage {
    	public abstract String getDescription();
    }
    
    package com.model.decorator;
    
    /**
     * 调味料摩卡装饰器,继承装饰器接口的具体装饰者
     * Created by Administrator on 2016/3/2.
     */
    public class Mocha extends CondimentDecorator {
    	Berverage berverage;
    
    	public Mocha (Berverage berverage) {
    		this.berverage = berverage;
    	}
    
    	@Override
    	public String getDescription() {
    		return berverage.getDescription() + ",Mocha";
    	}
    
    	@Override
    	public double cost() {
    		return 0.2 + berverage.cost();
    	}
    }
    
    package com.model.decorator;
    
    /**
     * 调味料Soy装饰器,继承装饰器的具体装饰者
     * Created by Administrator on 2016/3/2.
     */
    public class Soy extends CondimentDecorator {
    	Berverage berverage;
    
    	public Soy (Berverage berverage) {
    		this.berverage = berverage;
    	}
    
    	@Override
    	public String getDescription() {
    		return berverage.getDescription() + ",Soy";
    	}
    
    	@Override
    	public double cost() {
    		return 0.23 + berverage.cost();
    	}
    }
    
    package com.model.decorator;
    
    /**
     * Created by Administrator on 2016/3/2.
     */
    public class DecoratorTest {
    	public static void main(String[] args) {
    		Berverage berverage = new Espresso();
    		//不加任何调味料的浓咖啡
    		System.out.println(berverage.getDescription() + "$" + berverage.cost());
    		//添加摩卡的浓咖啡
    		berverage = new Mocha(berverage);
    		//添加soy的摩卡浓咖啡
    		berverage = new Soy(berverage);
    
    		//结账
    		System.out.println(berverage.getDescription() + "$" + berverage.cost());
    	}
    }
    
    执行结果:
    Espresso$1.99 Espresso,Mocha,Soy$2.42 Process finished with exit code 0

    7、深入装饰模式

    (1)模式功能
    装饰模式能够实现动态的为对象添加功能,是从一个对象外部来给对象增加功能,相当于是改变了对象的外观。当装饰过后,从外部使用系统的角度看,就不再是使用原始的那个对象了,而是使用被一系列的装饰器装饰过后的对象。
    这样就能够灵活的改变一个对象的功能,只要动态组合的装饰器发生了改变,那么最终所得到的对象的功能也就发生了改变。
    变相的还得到了另外一个好处,那就是装饰器功能的复用,可以给一个对象多次增加同一个装饰器,也可以用同一个装饰器装饰不同的对象。

    (2)对象组合
    前面已经讲到了,一个类的功能的扩展方式,可以是继承,也可以是功能更强大、更灵活的对象组合的方式。
    其实,现在在面向对象设计中,有一条很基本的规则就是“尽量使用对象组合,而不是对象继承”来扩展和复用功能。装饰模式的思考起点就是这个规则,可能有些朋友还不太熟悉什么是“对象组合”,下面介绍一下“对象组合”。

    (3)装饰器
    装饰器实现了对被装饰对象的某些装饰功能,可以在装饰器里面调用被装饰对象的功能,获取相应的值,这其实是一种递归调用。
    在装饰器里不仅仅是可以给被装饰对象增加功能,还可以根据需要选择是否调用被装饰对象的功能,如果不调用被装饰对象的功能,那就变成完全重新实现了,相当于动态修改了被装饰对象的功能。
    另外一点,各个装饰器之间最好是完全独立的功能,不要有依赖,这样在进行装饰组合的时候,才没有先后顺序的限制,也就是先装饰谁和后装饰谁都应该是一样的,否则会大大降低装饰器组合的灵活性。

    (4)装饰器和组件类的关系
    装饰器是用来装饰组件的,装饰器一定要实现和组件类一致的接口,保证它们是同一个类型,并具有同一个外观,这样组合完成的装饰才能够递归的调用下去。
    组件类是不知道装饰器的存在的,装饰器给组件添加功能是一种透明的包装,组件类毫不知情。需要改变的是外部使用组件类的地方,现在需要使用包装后的类,接口是一样的,但是具体的实现类发生了改变。

    (5)退化形式
    如果仅仅只是想要添加一个功能,就没有必要再设计装饰器的抽象类了,直接在装饰器里面实现跟组件一样的接口,然后实现相应的装饰功能就可以了。但是建议最好还是设计上装饰器的抽象类,这样有利于程序的扩展。

      

      

      

      

      

      

      

  • 相关阅读:
    SQL语法 之 基本查询
    Oracle 之 常用函数
    Tomcat 之 启动tomcat时 错误: 代理抛出异常 : java.rmi.server.ExportException: Port already in use: 1099;
    vim 如何编辑 GB2312 编码的文件?
    网络编程常见类型定义
    网络地址转换相关函数使用(inet_addr,inet_ntoa,inet_addr)
    onvif获取摄像头的流媒体地址完整流程
    gsoap
    海康ipc onvif抓包分析
    onvif杂项
  • 原文地址:https://www.cnblogs.com/glorytao/p/5239003.html
Copyright © 2020-2023  润新知