• 【韩老师设计模式6】装饰者和组装模式。FilterInputStream 和 HashMap


    装饰者

    星巴克咖啡订单项目(咖啡馆):

    1. 咖啡种类/单品咖啡: Espresso(意大利浓咖啡)、 ShortBlack、 LongBlack(美式
      咖啡)、 Decaf(无因咖啡)

    2. 调料: Milk、 Soy(豆浆)、 Chocolate

    3. 要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便

    4. 使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖
      啡+调料组合

    装饰者模式定义

    1. 装饰者模式: 动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更
      有弹性,装饰者模式也体现了开闭原则(ocp)

    2. 这里提到的动态的将新功能附加到对象和ocp原则,在后面的应用实例上会以代
      码的形式体现,请同学们注意体会。

    装饰者模式原理

    1. 装饰者模式就像打包一个快递
       主体: 比如:陶瓷、衣服 (Component) // 被装饰者
       包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)

    2. Component
      主体:比如类似前面的Drink

    3. ConcreteComponent和Decorator
      ConcreteComponent:具体的主体,
      比如前面的各个单品咖啡
      Decorator: 装饰者,比如各调料.

    4. 在如图的Component与ConcreteComponent之间,如果
      ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,
      抽象层一个类。

    • 顶层抽象类Component
      • 具体的 类:ConcreteComponent 。这里可以在 做一个 缓冲层
      • 装饰类 :Decorator,依赖 父类Component (继承 + 组合 父类)

    说明

    1. Drink 类就是前面说的抽象类, Component

    2. ShortBlack 就单品咖啡

    3. Decorator 是一个装饰类,含有一个被装饰的对象(Drink obj)

    4. Decorator 的cost 方法 进行一个费用的叠加计算,递归的计算价格

    说明

    1. Milk包含了LongBlack

    2. 一份Chocolate包含了(Milk+LongBlack)

    3. 一份Chocolate包含了(Chocolate+Milk+LongBlack)

    4. 这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护。

    • Chocolate
      • Chocolate
        • Milk
          • LongBlack 美式咖啡

    饮料抽象类

    public abstract class Drink {
        
    	public String des; // 描述
    	private float price = 0.0f;
        
        //get 和 set
    
    	//计算费用的抽象方法
    	//子类来实现
    	public abstract float cost();
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    中间层 和 实现

    public class Coffee  extends Drink {
    
    	@Override
    	public float cost() {
    		return super.getPrice();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    public class Espresso extends Coffee {
    	
    	public Espresso() {
    		setDes(" 意大利咖啡 ");
    		setPrice(6.0f);
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    装饰器类

    • 继承抽象类,还要 依赖抽象类
    public class Decorator extends Drink {
        //依赖的 是 咖啡
    	private Drink obj;
    	
    	public Decorator(Drink obj) { //组合
    		this.obj = obj;
    	}
    	
    	@Override
    	public float cost() {
    		// getPrice 自己价格
    		return super.getPrice() + obj.cost();
    	}
    	
    	@Override
    	public String getDes() {
    		// obj.getDes() 输出被装饰者的信息。自己的是 小件,糖,巧克力
    		return des + " " + getPrice() + " && " + obj.getDes();
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20

    具体的装饰者

    //具体的Decorator, 这里就是调味品
    public class Chocolate extends Decorator {
    
    	public Chocolate(Drink obj) {
    		super(obj);
    		setDes(" 巧克力 ");
    		setPrice(3.0f); // 调味品 的价格
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9

    使用装饰者

    		// 1. 点一份 LongBlack
    		Drink order = new LongBlack();
    		System.out.println("费用1=" + order.cost());
    		System.out.println("描述=" + order.getDes());
    
    		// 2. order 加入一份牛奶
    		order = new Milk(order);
    		System.out.println("order 加入一份牛奶 费用 =" + order.cost());
    		System.out.println("order 加入一份牛奶 描述 = " + order.getDes());
    
    		// 3. order 加入一份巧克力
    		order = new Chocolate(order);
    		System.out.println("order 加入一份牛奶 加入一份巧克力  费用 =" + order.cost());
    		System.out.println("order 加入一份牛奶 加入一份巧克力 描述 = " + order.getDes());
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    费用1=5.0
    描述= longblack 
    
    order 加入一份牛奶 费用 =7.0
    order 加入一份牛奶 描述 =  牛奶  2.0 &&  longblack 
    
    order 加入一份牛奶 加入一份巧克力  费用 =10.0
    order 加入一份牛奶 加入一份巧克力 描述 =  巧克力  3.0 &&  牛奶  2.0 &&  longblack 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8

    FilterInputStream

    InputStream 就是 drink

    • File Input Stream

    • String Buffer xx xx

    • Byte Array xx xx

    • Filter xx xx = 这个类似 装饰器

      • Buffer xx xx = 类似 具体的调味品,装饰的类
      • Data xx xx
      • Line Number xx xx
    • 说明

    1. InputStream 是抽象类, 类似我们前面讲的 Drink

    2. FileInputStream 是 InputStream 子类,类似我们前面的 DeCaf, LongBlack

    3. FilterInputStream 是 InputStream 子类:类似我们前面 的 Decorator 修饰者

      1. FilterInputStream 类 有 protected volatile InputStream in; 即含被装饰者
    4. DataInputStream 是 FilterInputStream 子类,具体的修饰者,类似前面的 Milk, Soy 等

    5. 分析得出在jdk 的io体系中,就是使用装饰者模式

    public abstract class InputStream implements Closeable{} //是一个抽象类,即Component
    
    public class FilterInputStream extends InputStream { //是一个装饰者类Decorator
    	protected volatile InputStream in //被装饰的对象 
    }
    
    class DataInputStream extends FilterInputStream implements DataInput { 
        //FilterInputStream 子类,也继承了 被装饰的对象 in
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    		DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt"));
    		System.out.println(dis.read()); //int 读取, A 65 ,a 97
    		dis.close();
    
    • 1
    • 2
    • 3

    组合模式

    把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是
    一个树形结构,可以更好的实现管理操作。 => 组合模式

    • 学校
      • 学院

    基本介绍

    1. 组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结
      构,将对象组合成树状结构以表示“整体-部分”的层次关系。

    2. 组合模式依据树形结构来组合对象,用来表示部分以及整体层次。

    3. 这种类型的设计模式属于结构型模式。

    4. 组合模式使得用户对单个对象和组合对象的访问具有一致性, 即:组合能让客
      户以一致的方式处理个别对象以及组合对象

    component 
    英 /kəmˈpəʊnənt/  美 /kəmˈpoʊnənt/  全球(美国)  
    简明 牛津 新牛津  韦氏  柯林斯 例句 百科
    n. 组成部份,成分,部件
    
    adj. 组成的,构成的
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • component
      • composite
        • leaf
    1. Component :这是组合中对象声明接口,在适当情况下,实现所有类共有的接口默认行为,用于访问和管理Component 子部件, Component 可以是抽象类或者接口
    2. Leaf 在组合中表示叶子节点,叶子节点 没有子节点
    3. Componsite 非叶子节点,用于存储部件,
      1. 在 Component 接口中 实现,子部件的相关操作,
      2. 比如:增加 删除

    Organization Component

    • add
    • remove
    • pring
      • University 聚合 College (代码写的是 上面的接口)
        • College
          • Department

    顶层接口

    public abstract class OrganizationComponent {
    
    	private String name; // 名字
    	private String des; // 说明
    	
    	protected  void add(OrganizationComponent c) {
    		//默认实现
    		throw new UnsupportedOperationException();
    	}
    	
    	protected  void remove(OrganizationComponent c) {
    		//默认实现
    		throw new 同上();
    	}
    
    	//构造器 和 get set
    	
    	//方法print, 做成抽象的, 子类都需要实现
    	protected abstract void print();
    	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21

    大学 和 学院 的类

    //University 就是 Composite , 可以管理College
    public class University extends OrganizationComponent {
    
    	List<OrganizationComponent> os = new ArrayList<OrganizationComponent>();
    
    	// 构造器
    	public University(String name, String des) {
    		super(name, des);
    	}
    
    	// 重写add
    	@Override
    	protected void add(OrganizationComponent c) {
    		os.add(c);
    	}
    
    	// 重写remove
    	@Override
    	protected void remove(OrganizationComponent c) {
    		os.remove(c);
    	}
    
    	@Override
    	public String getName() {
    		return super.getName();
    	}
    
    	@Override
    	public String getDes() {
    		return super.getDes();
    	}
    
    	// print方法,就是输出University 包含的学院
    	@Override
    	protected void print() {
    
    		System.out.println("--------------" + getName() + "--------------");
    		//遍历 organizationComponents 
    		for (OrganizationComponent c : os) {
    			c.print();
    		}
    	}
    }
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38
    • 39
    • 40
    • 41
    • 42
    • 43
    • 44
    public class College extends OrganizationComponent {
    
    	//List 中 存放的Department
    	list 的变量 os
    
    	//  将来实际业务中,Colleage 的 add 和  University add 不一定完全一样	
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7

    系的类

    public class Department extends OrganizationComponent {
    	//没有集合
    	public Department(String name, String des) {
    		super(name, des);
    	}
    
    	//add , remove 就不用写了,因为他是叶子节点
    	
    	@Override
    	public String getName() {
    		return super.getName();
    	}
    	
    	@Override
    	public String getDes() {
    		return super.getDes();
    	}
    	
    	@Override
    	protected void print() {
    		System.out.println(getName());
    	}
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23

    进行测试

    		//从大到小创建对象 学校
    		OrganizationComponent university = new University("清华大学", " 中国顶级大学 ");
    		
    		//创建 学院
    		OrganizationComponent computerCollege = new College("计算机学院", " 计算机学院 ");
    
    		//创建各个学院下面的系(专业)
    		computerCollege.add(new Department("软件工程", " 软件工程不错 "));
    		computerCollege.add(new Department("网络工程", " 网络工程不错 "));
    		computerCollege.add(new Department("计算机科学与技术", " 计算机科学与技术是老牌的专业 "));
    
    		
    		//将学院加入到 学校
    		university.add(computerCollege);
    
    		university.print();
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    --------------清华大学--------------
    --------------计算机学院--------------
    软件工程
    网络工程
    计算机科学与技术
    
    • 1
    • 2
    • 3
    • 4
    • 5

    HashMap

    Map<Integer,String> hashMap=new HashMap<Integer,String>();
    hashMap.put(0, "东游记");//直接存放叶子节点
    
    Map<Integer,String> map=new HashMap<Integer,String>();
    map.put(1, "西游记");
    map.put(2, "红楼梦"); //..
    hashMap.putAll(map);
    System.out.println(hashMap);
    
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    public interface Map<K,V> { //Component
    //add, remover..
    }
    
    //也相当于 Component
    public abstract class AbstractMap<K,V> implements Map<K,V> {
        
        public V put(K key, V value) {
            throw new UnsupportedOperationException();
        }
    }
    
    //相当于 大学 或 院系
    public class HashMap<K,V> extends AbstractMap<K,V>
        implements Map<K,V>, Cloneable, Serializable {
        
        //对 put 等进行了 实现 。
       	public V put(K key, V value) {
            return putVal(hash(key), key, value, false, true);
        }
        
        //最终把 node放入 HashMap
        final V putVal(int hash, K key, V value, boolean onlyIfAbsent,
                       boolean evict) {
            Node<K,V>[] tab; Node<K,V> p; int n, i;
        }
        
        //就是叶子 节点
    	static class Node<K,V> implements Map.Entry<K,V> {
            final int hash;
            final K key;
            V value;
            Node<K,V> next;
            
            //叶子节点,就没 put 了,主要是 get 和 set
    	}
        
    }
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11
    • 12
    • 13
    • 14
    • 15
    • 16
    • 17
    • 18
    • 19
    • 20
    • 21
    • 22
    • 23
    • 24
    • 25
    • 26
    • 27
    • 28
    • 29
    • 30
    • 31
    • 32
    • 33
    • 34
    • 35
    • 36
    • 37
    • 38

    组合模式的注意事项和细节

    1. 简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子
      的问题。

    2. 具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,
      客户端不用做出任何改动.

    3. 方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点
      或者叶子从而创建出复杂的树形结构

    4. 需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式.

    5. 要求较高的抽象性, 如果节点和叶子有很多差异性的话,比如很多方法和属性
      都不一样, 不适合使用组合模式

  • 相关阅读:
    Fooocus框架代码分析
    【消息中间件】RocketMQ设计浅析
    selenium + robotframework的运行原理
    工厂3d模拟展示虚拟漫游彰显企业实力和竞争力
    Visual Studio清单作用
    PHP检测一个字符串中是否包含另外一个字符或字符串
    sqlserver2012 完全卸载
    啥?PS一秒成图?Adobe的逆天黑科技大公开
    系列七、栈 & 堆
    MyBatisplus使用报错--Invalid bound statement
  • 原文地址:https://blog.csdn.net/qq120631157/article/details/125431676