装饰模式

动态的给一个对象添加一些额外的职责,比生成子类更加灵活

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
// ICharacter.java
public interface ICharacter {
public void show();
}

// Person.java
public class Person implements ICharacter{
private String name;
public Person(String n){
name = n;
}

@Override
public void show() {
System.out.println("装饰的" + name);
}
}

// Finery.java
public class Finery implements ICharacter{
protected ICharacter component;
public void decorate(ICharacter com){
component = com;
}

@Override
public void show() {
if (component != null) component.show();
}

}

// Tshirts.java
public class Tshirts extends Finery{
public void show(){
System.out.println("大T恤");
super.show();
}
}

// Main.java
public static void main(String[] args) {
Person xc = new Person("sss");
Sneakers qx = new Sneakers();
qx.decorate(xc);
BigTrouser kk = new BigTrouser();
kk.decorate(qx);
Tshirts tx = new Tshirts();
tx.decorate(kk);
tx.show();
}
  1. 创建抽象接口类 Component,定义给对象冬天的添加职责的公共接口
  2. 创建具体的接口Person(ConcreteComponent)继承Component,定义Show()用于展示结果
  3. 创建抽象的装饰类Finery(Decorator),继承Component,定义Decorate(component)用于进行装扮的过程;重写Show()具体装扮结果
  4. 创建具体的服饰类,Concrete Decorator,继承Decorator,实现具体的装饰对象,并重写Show()显示具体装扮结果

四类角色

  1. 实体接口: 定义对象接口,动态添加职责
  2. 实体类
  3. 装饰抽象类: 继承实体接口,动态扩展职责
  4. 具体装饰类: 装饰的具体实现

D

可以不生成很多子类的情况下扩展类,比如商场打折促销,不仅可以使用策略模式,还可以使用装饰模式,实现打折基础上再进行满减活动
通知信息也有很多渠道,比如短信,微信,qq,邮件系统,多种信息组合通知可以使用装饰模式避免组合

优点:

  • 把类中的装饰功能从类中去除,简化原有的类
  • 把类的核心职责和装饰功能区分,去除重复的装饰逻辑
  • 装饰类和被装饰类独立发展,不会相互耦合
  • 不需要创建新的子类即可实现对类功能的动态扩展
  • 支持运行时添加或者删除对象的功能
  • 满足单一职责原则,可以将不同行为的类拆分成多个较小的类
    缺点:
  • 在封装器栈中删除特定封装器较为困难
  • 较难实现行为不受先后顺序影响的装饰
  • 各个装饰层的代码相对冗余

工厂 + 策略 + 装饰实现商场打折

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
// ISale.java
public interface ISale {
public double acceptCash(double price, int num);
}

// CashSuper.java
public class CashSuper implements ISale{
protected ISale component;
public void decorate(ISale com){
component = com;
}

public double acceptCash(double price, int num) {
double ans = 0;
if (component != null) component.acceptCash(price, num);
return ans;
}
}

// CashNormal.java
public class CashNormal implements ISale{
@Override
public double acceptCash(double price, int num){
return price * num;
}
}

// CashRebate.java
public class CashRebate extends CashSuper{
private double moneyRebate = 1;
public CashRebate(double mR){
moneyRebate = mR;
}

@Override
public double acceptCash(double price, int num) {
double ans = price * num * moneyRebate;
return super.acceptCash(ans, 1);
}
}

// CashReturn.java
public class CashReturn extends CashSuper{
private double moneyCondition = 0;
private double moneyReturn = 0;
public CashReturn(double mC, double mR){
moneyCondition = mC;
moneyReturn = mR;
}

public double acceptCash(double price, int num){
double ans = price * num;
if (moneyCondition > 0 && ans >= moneyCondition){
ans -= Math.floor(ans / moneyCondition) * moneyReturn;
}
return super.acceptCash(ans, 1);
}
}
// CashContext.java
public class CashContext {
private ISale cs;
public CashContext(int cashType){
switch (cashType) {
case 1:
cs = new CashNormal();
break;
case 2:
cs = new CashReturn(300, 100);
break;
case 3:
cs = new CashRebate(0.8);
break;
case 4:
cs = new CashRebate(0.7);
break;
case 5:
// 先200 - 50再打八折
CashNormal cn = new CashNormal();
CashRebate cr = new CashRebate(0.8);
CashReturn crr = new CashReturn(200, 50);
cr.decorate(cn);
crr.decorate(cr);
cs = crr;
break;
default:
break;
}
}
public double getResult(double price, int num){
return cs.acceptCash(price, num);
}
}

代理模式

为其他对象提供代理以控制这个对象的访问

P

代理模式

  1. 本地执行远程服务(远程代理): 适用于服务对象位于远程服务器上的情形,可以为一个对象在不同的地址空间提供局部代表
  2. 延迟初始化(虚拟代理): 如果有一个偶尔使用的重量级服务对象,一直保持对象的运行会消耗系统资源,就可以使用代理模式,比如浏览器加载图片,可以先加载图片的位置以及大小,然后再慢慢渲染出图片
  3. 访问控制(保护代理/安全代理): 如果只希望特定客户端使用服务对象,对象可以是操作系统中的重要部分,而客户端则是各种已经启动的程序,就可以使用代理模式
  4. 记录日志请求(日志记录代理): 适用于需要保存对服务对象的请求历史记录
  5. 缓存请求结果(缓存代理): 适用于需要缓存客户请求并对缓存生命周期进行管理时,特别是返回结果体积非常大的时候
  6. 智能指引: 调用真实对象是,代理处理另外一些事情,可以在没有客户端使用某个重量级对象时,立刻销毁对象

比如信用卡是银行账户的代理;银行账户是现金的代理;windows快捷方式也是代理;客户端对数据库查询需要消耗大量的资源,在有需要时才创建会带来代码大量重复,因此可以创建代理,让代理伪装成数据库对象,在客户端不知情的情况下处理初始化以及缓存查询结果