星巴克咖啡订单项目(咖啡馆):
咖啡种类/单品咖啡: Espresso(意大利浓咖啡)、 ShortBlack、 LongBlack(美式
咖啡)、 Decaf(无因咖啡)
调料: Milk、 Soy(豆浆)、 Chocolate
要求在扩展新的咖啡种类时,具有良好的扩展性、改动方便、维护方便
使用OO的来计算不同种类咖啡的费用: 客户可以点单品咖啡,也可以单品咖
啡+调料组合
装饰者模式定义
装饰者模式: 动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更
有弹性,装饰者模式也体现了开闭原则(ocp)
这里提到的动态的将新功能附加到对象和ocp原则,在后面的应用实例上会以代
码的形式体现,请同学们注意体会。
装饰者模式原理
装饰者模式就像打包一个快递
主体: 比如:陶瓷、衣服 (Component) // 被装饰者
包装:比如:报纸填充、塑料泡沫、纸板、木板(Decorator)
Component
主体:比如类似前面的Drink
ConcreteComponent和Decorator
ConcreteComponent:具体的主体,
比如前面的各个单品咖啡
Decorator: 装饰者,比如各调料.
在如图的Component与ConcreteComponent之间,如果
ConcreteComponent类很多,还可以设计一个缓冲层,将共有的部分提取出来,
抽象层一个类。
说明
Drink 类就是前面说的抽象类, Component
ShortBlack 就单品咖啡
Decorator 是一个装饰类,含有一个被装饰的对象(Drink obj)
Decorator 的cost 方法 进行一个费用的叠加计算,递归的计算价格
说明
Milk包含了LongBlack
一份Chocolate包含了(Milk+LongBlack)
一份Chocolate包含了(Chocolate+Milk+LongBlack)
这样不管是什么形式的单品咖啡+调料组合,通过递归方式可以方便的组合和维护。
public abstract class Drink {
public String des; // 描述
private float price = 0.0f;
//get 和 set
//计算费用的抽象方法
//子类来实现
public abstract float cost();
}
public class Coffee extends Drink {
@Override
public float cost() {
return super.getPrice();
}
}
public class Espresso extends Coffee {
public Espresso() {
setDes(" 意大利咖啡 ");
setPrice(6.0f);
}
}
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();
}
}
//具体的Decorator, 这里就是调味品
public class Chocolate extends Decorator {
public Chocolate(Drink obj) {
super(obj);
setDes(" 巧克力 ");
setPrice(3.0f); // 调味品 的价格
}
}
// 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=5.0
描述= longblack
order 加入一份牛奶 费用 =7.0
order 加入一份牛奶 描述 = 牛奶 2.0 && longblack
order 加入一份牛奶 加入一份巧克力 费用 =10.0
order 加入一份牛奶 加入一份巧克力 描述 = 巧克力 3.0 && 牛奶 2.0 && longblack
InputStream 就是 drink
File Input Stream
String Buffer xx xx
Byte Array xx xx
Filter xx xx = 这个类似 装饰器
说明
InputStream 是抽象类, 类似我们前面讲的 Drink
FileInputStream 是 InputStream 子类,类似我们前面的 DeCaf, LongBlack
FilterInputStream 是 InputStream 子类:类似我们前面 的 Decorator 修饰者
DataInputStream 是 FilterInputStream 子类,具体的修饰者,类似前面的 Milk, Soy 等
分析得出在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
}
DataInputStream dis = new DataInputStream(new FileInputStream("d:\\abc.txt"));
System.out.println(dis.read()); //int 读取, A 65 ,a 97
dis.close();
把学校、院、系都看做是组织结构,他们之间没有继承的关系,而是
一个树形结构,可以更好的实现管理操作。 => 组合模式
基本介绍
组合模式(Composite Pattern),又叫部分整体模式,它创建了对象组的树形结
构,将对象组合成树状结构以表示“整体-部分”的层次关系。
组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
这种类型的设计模式属于结构型模式。
组合模式使得用户对单个对象和组合对象的访问具有一致性, 即:组合能让客
户以一致的方式处理个别对象以及组合对象
component
英 /kəmˈpəʊnənt/ 美 /kəmˈpoʊnənt/ 全球(美国)
简明 牛津 新牛津 韦氏 柯林斯 例句 百科
n. 组成部份,成分,部件
adj. 组成的,构成的
Organization Component
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();
}
//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();
}
}
}
public class College extends OrganizationComponent {
//List 中 存放的Department
list 的变量 os
// 将来实际业务中,Colleage 的 add 和 University add 不一定完全一样
}
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());
}
}
//从大到小创建对象 学校
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();
--------------清华大学--------------
--------------计算机学院--------------
软件工程
网络工程
计算机科学与技术
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);
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
}
}
组合模式的注意事项和细节
简化客户端操作。客户端只需要面对一致的对象而不用考虑整体部分或者节点叶子
的问题。
具有较强的扩展性。当我们要更改组合对象时,我们只需要调整内部的层次关系,
客户端不用做出任何改动.
方便创建出复杂的层次结构。客户端不用理会组合里面的组成细节,容易添加节点
或者叶子从而创建出复杂的树形结构
需要遍历组织机构,或者处理的对象具有树形结构时, 非常适合使用组合模式.
要求较高的抽象性, 如果节点和叶子有很多差异性的话,比如很多方法和属性
都不一样, 不适合使用组合模式