装饰者设计模式
装饰模式(Decorator)又称之为包装模式.主要作用是动态的为一个对象增加新的功能。
装饰器模式是可用于代替继承,无需通过继承增加子类就能扩展对象的新功能。就增加功能来说,装饰模式相比生成子类更为灵活。,同时避免类型体系的快速膨胀。
其通用类关系图如下
每个角色的说明
- 抽象构件:给出一个抽象接口或抽象类来规范准备接收附加功能的对象
- 具体构件:定义一个将要接受附加功能的类,即被装饰类
- 装饰角色:持有一个抽象构件对象的实例,并在对应方法中执行构件对象的方法
- 具体装饰:负责给构件对象增加新的功能
装饰者与被装饰者拥有共同的超类,继承的目的是继承类型,而不是行为
实例说明
//Component 英雄接口(抽象构建)
public interface Hero {
/**
* 学习技能
*/
void learnSKills();
}
/**
* 被装饰者(具体构件)
*/
public static class BlindMonk implements Hero{
private String name;
public BlindMonk(String name) {
this.name = name;
}
@Override
public void learnSKills() {
System.out.print(name+":升级成功!\n");
}
}
/**
* 技能栏 装饰者
*/
public static class Skills implements Hero{
private Hero mHero;
public Skills(Hero hero) {
mHero = hero;
}
@Override
public void learnSKills() {
mHero.learnSKills();
}
}
/**
* 具体的装饰器
*/
public static class Skill_Q extends Skills{
public Skill_Q(Hero hero) {
super(hero);
}
@Override
public void learnSKills() {
System.out.print("学习了技能Q:天音波/回音击\n");
super.learnSKills();
}
}
/**
* 具体的装饰器
*/
public static class Skill_W extends Skills{
public Skill_W(Hero hero) {
super(hero);
}
@Override
public void learnSKills() {
System.out.print("学习了技能W:金钟罩/铁布衫\n");
super.learnSKills();
}
}
/**
* 具体的装饰器
*/
public static class Skill_E extends Skills{
public Skill_E(Hero hero) {
super(hero);
}
@Override
public void learnSKills() {
System.out.print("学习了技能E:天雷破/摧筋断骨\n");
super.learnSKills();
}
}
/**
* 具体的装饰器
*/
public static class Skill_R extends Skills{
public Skill_R(Hero hero) {
super(hero);
}
@Override
public void learnSKills() {
System.out.print("学习了技能R:猛龙摆尾\n");
super.learnSKills();
}
}
/**
* 装饰者模式测试
*/
private static void Test() {
Zhuangshizhe.BlindMonk blindMonk=new Zhuangshizhe.BlindMonk("瞎子");
Zhuangshizhe.Skill_R skillR=new Zhuangshizhe.Skill_R(blindMonk);
Zhuangshizhe.Skill_E skillE=new Zhuangshizhe.Skill_E(skillR);
Zhuangshizhe.Skill_W skillW=new Zhuangshizhe.Skill_W(skillE);
Zhuangshizhe.Skill_Q skillQ=new Zhuangshizhe.Skill_Q(skillW);
skillQ.learnSKills();
}
返回结果如下:
学习了技能Q:天音波/回音击
学习了技能W:金钟罩/铁布衫
学习了技能E:天雷破/摧筋断骨
学习了技能R:猛龙摆尾
瞎子:升级成功!
半透明的装饰模式
其类关系图如下
java中使用装饰模式最经典的就是I/O标准库的设计了,下面以InputStream为例说明
我们把InputStream,FilterInputStream,
/**
* InputStream 具体构件
*/
public abstract class InputStream implements Closeable {
private static final int MAX_SKIP_BUFFER_SIZE = 2048;
public abstract int read() throws IOException;
public int read(byte b[]) throws IOException {}
public int read(byte b[], int off, int len) throws IOException {}
public long skip(long n) throws IOException {}
public int available() throws IOException {}
public void close() throws IOException {}
public synchronized void mark(int readlimit) {}
public synchronized void reset() throws IOException {}
public boolean markSupported() {}
}
/**
* FilterInputStream 装饰角色 有一个InputStream的引用 并且
*/
public class FilterInputStream extends InputStream {
protected volatile InputStream in;
protected FilterInputStream(InputStream in) {
this.in = in;
}
public int read() throws IOException {
return in.read();
}
public int read(byte b[]) throws IOException {
return read(b, 0, b.length);
}
public int read(byte b[], int off, int len) throws IOException {
return in.read(b, off, len);
}
public long skip(long n) throws IOException {
return in.skip(n);
}
public int available() throws IOException {
return in.available();
}
public void close() throws IOException {
in.close();
}
public synchronized void mark(int readlimit) {
in.mark(readlimit);
}
public synchronized void reset() throws IOException {
in.reset();
}
public boolean markSupported() {
return in.markSupported();
}
}
那么很明显FilterInputStream的子类就是具体的装饰器分别是BufferedInputStream、DataInputStream以及LineNumberInputStream、PushbackInputStream。
装饰者和代理之间的区别
首先目的不同,装饰者模式是为了扩展被装饰着的功能,主要是增加,而代理却是对被代理的对象进行了限制可以在通过条件来控制是否执行被代理对象的具体方法.以上面瞎子为例,装饰者模式可以帮助瞎子使用各种连招.什么RQ R闪等,但是代理模式则是根据当前的cd能量等级等判断该技能是否能打出来.再从形式上来说使用代理模式,代理和真实对象之间的的关系通常在编译时就已经确定了,而装饰者能够在运行时递归地被构造。我个人觉得吧 形式倒是无关紧要,目的性最要紧,协同开发中你说你这个是代理模式,那么你的小伙伴就是向限制性上考虑,同理规定这个是装饰者那么就是增强功能方面考虑.