与复用性有关的设计模式

AdapterDecoratorFacade

Structural patterns

Adapter

将某个类/接口转换为client期望的其他形式

Adapter

Decorator

当需要特性的任意组合的时候,可以用装饰器模式

subtyping + delegation

抽象构件(Component)角色:给出一个抽象接口,以规范准备接收附加责任的对象。
具体构件(ConcreteComponent)角色:定义一个将要接收附加责任的类
装饰角色(Decorator):持有一个构件(Component)对象的实例,并定义一个与抽象构件接口一致的接口
具体装饰角色(ConcreteDecorator):负责给构件对象“贴上”附加的责任

Decorator

举个例子:

咖啡是一种饮料,咖啡的本质是咖啡豆+水磨出来的。咖啡店现在要卖各种口味的咖啡,如果不使用装饰模式,那么在销售系统中,各种不一样的咖啡都要产生一个类,如果有4中咖啡豆,5种口味,那么将要产生至少20个类(不包括混合口味),非常麻烦。使用了装饰模式,只需要11个类即可生产任意口味咖啡(包括混合口味)。

coffee

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
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
public interface Beverage {
//返回商品描述
public String getDescription();
//返回价格
public double getPrice();
}
//具体被装饰的对象类1
public class CoffeeBean1 implements Beverage {
private String description = "选了第一种咖啡豆";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 50;
}
}
//具体被装饰的对象类2
public class CoffeeBean2 implements Beverage {
private String description = "第二种咖啡豆!";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 100;
}
}
//装饰器
public class Decorator implements Beverage {
private String description = "我只是装饰器,不知道具体的描述";
@Override
public String getDescription() {
return description;
}
@Override
public double getPrice() {
return 0; //价格由子类来决定
}
}
public class Milk extends Decorator{
private String description = "加了牛奶!";
private Beverage beverage = null;
public Milk(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+20; //20表示牛奶的价格
}
}
public class Mocha extends Decorator {
private String description = "加了摩卡!";
private Beverage beverage = null;
public Mocha(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+49; //30表示摩卡的价格
}
}
public class Soy extends Decorator {
private String description = "加了豆浆!";
private Beverage beverage = null;
public Soy(Beverage beverage){
this.beverage = beverage;
}
public String getDescription(){
return beverage.getDescription()+"\n"+description;
}
public double getPrice(){
return beverage.getPrice()+30; //30表示豆浆的价格
}
}

//test
public class Test {

public static void main(String[] args) {
Beverage beverage = new CoffeeBean1(); //选择了第一种咖啡豆磨制的咖啡
beverage = new Mocha(beverage); //为咖啡加了摩卡
beverage = new Milk(beverage); //为咖啡加了牛奶
System.out.println(beverage.getDescription()+"\n加了摩卡和牛奶的咖啡价格:"+beverage.getPrice());

}
}
//结果
选了第一种咖啡店
加入了摩卡!
加入了牛奶!
加了摩卡和牛奶的咖啡价格:119.0

重要的一点补充:

装饰模式对客户端的透明性要求程序不要声明一个ConcreteComponent类型的变量,而应当声明一个Component类型的变量。

用上面的例子来说,必须永远把所有的饮料当成饮料来对待,而如果把饮料变成的加摩卡的饮料当成摩卡,而不是饮料,这是不应当发生的。

Adapter和Decorator的关系

装饰模式和适配器模式都是“包装模式(Wrapper Pattern)”,它们都是通过封装其他对象达到设计的目的的。

区别:

理想的装饰模式在对被装饰对象进行功能增强的同时,要求具体构件角色、装饰角色的接口与抽象构件角色的接口完全一致。

适配器模式并不要求对源对象的功能进行增强,但是会改变源对象的接口,以便和目标接口相符合。

拓展:

并且,装饰模式有透明和半透明两种,这两种的区别就在于装饰角色的接口与抽象构件角色的接口是否完全一致。

透明的装饰模式也就是理想的装饰模式。半透明的装饰器模式如下图:

透明,半透明,不透明

Facade

客户端需要通过一个简化的接口来访问复杂系统内的功能

但Façade设计模式并非一个集装箱,可以任意地放进任何多个对象。Façade模式中组件的内部应该是“相互耦合关系比较大的一系列组件”,而不是一个简单的功能集合。

Facade

Bridge(补充)

桥接(Bridge)模式的定义如下:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度。

Bridge

以女士皮包为例:

女士皮包有很多种,用途分可选钱包(Wallet)和挎包(Handbag),按颜色分可选黄色(Yellow)和红色(Red)

颜色类(Color)是一个维度,定义为实现化角色,它有两个具体实现化角色:黄色和红色,通过 getColor() 方法可以选择颜色;包类(Bag)是另一个维度,定义为抽象化角色,它有两个扩展抽象化角色:挎包和钱包,它包含了颜色类对象,通过 getName() 方法可以选择相关颜色的挎包和钱包。

Bridge例子

区分Façade、Adapter、Bridge与Decorator

Façade模式注重简化接口

Adapter模式注重转换接口

Bridge模式注重分离接口(抽象)与其实现

Decorator模式注重稳定接口的前提下为对象扩展功能。

Behavioral patterns

Strategy

为不同的实现算 法构造抽象接口,利用delegation,运行时动态传入client倾向的算法 类实例

Strategy

Template

共性的步骤在抽象类内公共实现,差 异化的步骤在各个子类中实现

inheritance + overridable

Template

Iterator

对放入集合类里的ADT提供统一的遍历方法

Iterator 迭代器接口
ConcreateIterator 具体实现类
Aggregate 集合类接口
ConcreteAggregate 具体的集合类

Iterator

好处:

一个重要的原因,引入 Iterator 后可以将遍历与实现分离出来。

不论具体集合类如何实现(数组or链表),下面的遍历代码都不用改动

1
2
3
while (iterator.hasNext()) {
System.out.println(iterator.next().getName());
}

未完待续。。。

try-catch-finally

1
2
3
4
5
6
7
8
9
10
11
public static boolean test() {
try {
return true;
}finally {
return false;
}
}
public static void main(String []args)
{
System.out.print(test());
}

return false

You forgot to set the qrcode for Alipay. Please set it in _config.yml.
You forgot to set the qrcode for Wechat. Please set it in _config.yml.
You forgot to set the business and currency_code for Paypal. Please set it in _config.yml.
You forgot to set the url Patreon. Please set it in _config.yml.
Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×