装饰者模式

装饰者模式动态地将责任附加到对象上,若要扩展功能,装饰着提供了比继承更具有弹性的替代方案。

  • 装饰者和被装饰者对象有相同的超类型
  • 可以用一个或多个装饰者包装一个对象
  • 既然装饰者和被装饰者对象有相同的超类型,所以在包装后,可以用装饰过的对象替代它
  • 装饰者可以在所委托被装饰者的行为之前与/或之后,加上自己的行为,以达到特定的目的
  • 对象可以在任何时候被装饰,所以可以在运行时动态的、不受限的装饰对象

一个易理解的实例:

装饰模式为已有类动态附加额外的功能就像LOL、王者荣耀等类Dota游戏中,英雄升级一样。每次英雄升级都会附加一个额外技能点学习技能。具体的英雄就是ConcreteComponent,技能栏就是装饰器Decorator,每个技能就是ConcreteDecorator。

Component 英雄接口

1
2
3
4
public interface Hero {
//学习技能
void learnSkills();
}

ConcreteComponent 具体英雄盲僧

1
2
3
4
5
6
7
8
9
10
11
12
13
public class BlindMonk implements Hero {

private String name;

public BlindMonk(String name) {
this.name = name;
}

@Override
public void learnSkills() {
System.out.println(name + "学习了以上技能!");
}
}

Decorator 技能栏

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
public class Skills implements Hero{

//持有一个英雄对象接口
private Hero hero;

public Skills(Hero hero) {
this.hero = hero;
}

@Override
public void learnSkills() {
if(hero != null)
hero.learnSkills();
}
}

ConreteDecorator 具体的技能实现:Q

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
public class Skill_Q extends Skills{

private String skillName;

public Skill_Q(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
}

@Override
public void learnSkills() {
System.out.println("学习了技能Q:" +skillName);
super.learnSkills();
}
}
//更多的技能
... ...
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
//客户端:召唤师
public class Player {
public static void main(String[] args) {
//选择英雄
Hero hero = new BlindMonk("李青");

Skills skills = new Skills(hero);
Skills r = new Skill_R(skills,"猛龙摆尾");
Skills e = new Skill_E(r,"天雷破/摧筋断骨");
Skills w = new Skill_W(e,"金钟罩/铁布衫");
Skills q = new Skill_Q(w,"天音波/回音击");
//学习技能
q.learnSkills();
}
}

输出:

1
2
3
4
5
学习了技能Q:天音波/回音击
学习了技能W:金钟罩/铁布衫
学习了技能E:天雷破/摧筋断骨
学习了技能R:猛龙摆尾
李青学习了以上技能!

java内部的装饰者模式应用——I/O类

编写一个I/O装饰者

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
public class LowerCaseInputStream extends FilterInputStream {
public LowerCaseInputStream(InputStream in) {
super(in);
}

public int read() throws IOException {
int c = super.read();
return (c == -1 ? c : Character.toLowerCase((char)c)));
}

public int read(byte[] b, int offset, int len) throws IOException {
int result = super.read(b, offset, len);
for(int i = offset; i < offset + result; i++) {
b[i] = (byte)Character.toLowerCase((char)b[i]);
}
return result;
}
}

设计原则

类应该对扩展开放,对修改关闭。也就是说,我们的目标是允许类容易扩展,在不修改现有代码的情况下添加新的行为。这样的设计具有了弹性可以应对改变。

联系我

评论