装饰器模式,就是包装模式(Wrapper)模式。包装的含义就是对一个原先存在的类进行扩展。
一般进行扩展时有两个方案,继承或者组合,但是不鼓励继承,一般使用组合来扩展功能。
装饰器中的角色有:
1. 抽象构建角色
给出一个抽象接口,用来规范准备接受附加责任的对象。
2.具体构件角色
定义一个将要接受附加责任的类
3.装饰角色
持有一个构件对象的实例,定义一个与抽象构件角色接口一致的接口
4.具体装饰角色
负责给构件对象贴上附加的责任
例子可以以Dota的英雄学习技能为例子,Hero就是抽象构件,而具体的英雄就是继承它的,而技能框就是装饰角色(Skills),具体的装饰角色就是技能点。
/**
* @author: wayne
* @desc: 抽象构件角色---英雄接口,规范接口
* @date: 2018/1/2 14:06
* @version: 1.0
*/
public interface Hero {
/**
* 学习技能接口
*/
public void learnSkills();
}
/**
* @author: wayne
* @desc: 具体构件角色--英雄Dr
* @date: 2018/1/2 14:13
* @version: 1.0
*/
public class Dr implements Hero {
private String name;
public Dr(String name) {
this.name = name;
}
@Override
public void learnSkills() {
System.out.println(name + "学习过技能");
}
}
/**
* @author: wayne
* @desc: 装饰角色---技能栏,技能分4个
* @date: 2018/1/2 14:17
* @version: 1.0
*/
public class Skills implements Hero{
private Hero hero;
public Skills(Hero hero) {
this.hero = hero;
}
@Override
public void learnSkills() {
hero.learnSkills();
}
}
/**
* @author: wayne
* @desc: 技能--E
* @date: 2018/1/2 14:19
* @version: 1.0
*/
public class SkillE extends Skills{
private String skillName;
public SkillE(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public void learnSkills() {
System.out.println("学习了技能点:"+skillName);
super.learnSkills();
}
}
/**
* @author: wayne
* @desc: 技能M
* @date: 2018/1/2 14:21
* @version: 1.0
*/
public class SkillM extends Skills{
private String skillName;
public SkillM(Hero hero, String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public void learnSkills() {
System.out.println("学习了技能点:"+skillName);
super.learnSkills();
}
}
/**
* @author: wayne
* @desc: 技能R
* @date: 2018/1/2 14:21
* @version: 1.0
*/
public class SkillR extends Skills{
private String skillName;
public SkillR(Hero hero,String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public void learnSkills() {
System.out.println("学习了技能点:"+skillName);
super.learnSkills();
}
}
/**
* @author: wayne
* @desc: 技能T
* @date: 2018/1/2 14:21
* @version: 1.0
*/
public class SkillT extends Skills{
private String skillName;
public SkillT(Hero hero, String skillName) {
super(hero);
this.skillName = skillName;
}
@Override
public void learnSkills() {
System.out.println("学习了技能点:"+skillName);
super.learnSkills();
}
}
/**
* @author: wayne
* @desc:
* @date: 2018/1/2 14:23
* @version: 1.0
*/
public class Player {
public static void main(String[] args) {
Hero hero = new Dr("黑暗游侠");
Skills skills = new Skills(hero);
Skills m = new SkillM(skills,"M--射手天赋");
Skills r = new SkillR(m,"R--霜冻之箭");
Skills t = new SkillT(r,"T--强击光环");
Skills e = new SkillE(t,"E--沉默魔法");
e.learnSkills();
}
}
学习了技能点:E--沉默魔法
学习了技能点:T--强击光环
学习了技能点:R--霜冻之箭
学习了技能点:M--射手天赋
黑暗游侠学习过技能
动手写了一下装饰器结构的代码,有了一点认识之后,可以再去看看Java I/O部分的构造,I/O部分使用的就是装饰器模式。
File file = new File("D:/test.txt");
InputStream s = new FileInputStream(file);
BufferedInputStream bfs = new BufferedInputStream(s);
这是我们平时写IO时常写的结构,打开一个File,构建一个输入流,或许还需要构建一个Buffed的输入流。这就是装饰。
1. 首先来看InputStream。代码不全贴了,可以看出它是一个抽象类,并且它是一个顶层的接口,在IO模式里,它上面没有任何父类了,因此可以认为它是一个抽象构件角色,联系例子中来理解,它就是Hero接口,定义了一套规范。。。。
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 {
return read(b, 0, b.length);
}
}
2.FileInputStream,可以看见它是继承于InputStream,那么可以对应出它是Dr, 也就是具体构件对象。
public class FileInputStream extends InputStream {
/* File Descriptor - handle to the open file */
private final FileDescriptor fd;
private FileChannel channel = null;
}
3.在BufferedInputStream中,可以看见它继承于FilterInputStream。那么我们可以猜测, FilterInputStream必定是装饰角色了,就类似于上面的Skills,技能栏。而 BufferedInputStream就是具体的装饰角色,就是上面的4个技能点。
public class BufferedInputStream extends FilterInputStream {
private static int defaultBufferSize = 8192;
/**
* The internal buffer array where the data is stored. When necessary,
* it may be replaced by another array of
* a different size.
*/
protected volatile byte buf[];
}
4.FilterInputStream继承于InputStream这个顶级接口,保留了InputStream的引用。
public class FilterInputStream extends InputStream {
/**
* The input stream to be filtered.
*/
protected volatile InputStream in;
}
参考链接:装饰器模式