装饰者模式:动态的给对象添加一些额外的职责,就功能来说装饰者模式相比生成子类更为灵活.
在许多设计中,一些类的设计人员经常遇到这样的问题:可能需要改进类的某个对象的功能,而不是改进该类创建的全部对象.
面对这样的问题,不用担心,装饰者模式是动态的扩展一个对象的功能,而不需要修改原始代码的一种成熟模式.
装饰者模式结构中包括四个角色:
抽象组件:抽象组件是一个抽象类,定义了被装饰者需要装饰的方法.
具体组件:具体组件是抽象组件类一个子类,他的实例称作"被装饰者".
装饰:装饰也是抽象组件类的一个子类,但装饰类还包含一个抽象组件声明的变量以保存具体组件的引用.
具体装饰:具体装饰是装饰类的一个子类,他的实例称作"装饰者"
应用场景一:
某个生产玩具的电子厂生产了一批电子麻雀,他们的飞行距离都是100米,现在用户提出新需求:要求某些麻雀可以飞行150米,200米或者其他距离.
有一个功能是:用户可以通过ReadeWord类的子类ReadEnglishWord读取english.txt文件中的单词.现在有些用户希望同时得到该单词的汉语解释,
同时也有一些用户希望不仅可以得到该单词的汉语解释也能得到该单词的英文例句.前提是:不允许用户修改系统现有的代码和english.txt文件.
1.被装饰者和装饰者是松耦合关系,由于装饰仅仅依赖于抽象组件,因此具体装饰只知道他要装饰的对象是抽象组件的某个子类的实例,
但不需要知道是哪一个具体子类.
2.装饰者模式满足"开闭原则",不必修改具体组件,就可以增加新的针对该具体组件的具体装饰.
3.可以使用多个具体装饰装饰具体组件实例.
知识补充:
sun公司在设计java.io包中的类时使用了装饰者模式.
1.java.io包中的InputStream类是一个抽象类,该类的子类和间接子类称作字节输入流.
2.java.io包中的Reader类也是一个抽象类,该类的子类或间接子类称作字符输入流.
下面以Reader为例说明java.io是如何通过装饰者模式来设计类的.
Reader相当于装饰者模式中的抽象组件,FileReader相当于装饰者模式中的具体组件,即被装饰者,而BufferedReader相当于装饰者中的装饰.
需要注意的是:readLine()方法是BufferedReader新增的方法,用户必须使用BufferedReader才能调用该方法.BufferedReader对象在调用read
方法读取文件中的一个字符时,首先委托FileReader对象将字符读入缓存,然后BufferedReader再从缓存中读取字符.BufferedReader对象在使用
readLine()方法读取文件的一行时,首先委托FileReader对象将足够的字符读入缓存,然后BufferedReader对象从缓存中读取一行字符.
即:BufferedReader br = new BufferedReader(new FileReader(new File("E:/a.txt")));另外可以参照源码分析.
在许多设计中,一些类的设计人员经常遇到这样的问题:可能需要改进类的某个对象的功能,而不是改进该类创建的全部对象.
面对这样的问题,不用担心,装饰者模式是动态的扩展一个对象的功能,而不需要修改原始代码的一种成熟模式.
装饰者模式结构中包括四个角色:
抽象组件:抽象组件是一个抽象类,定义了被装饰者需要装饰的方法.
具体组件:具体组件是抽象组件类一个子类,他的实例称作"被装饰者".
装饰:装饰也是抽象组件类的一个子类,但装饰类还包含一个抽象组件声明的变量以保存具体组件的引用.
具体装饰:具体装饰是装饰类的一个子类,他的实例称作"装饰者"
应用场景一:
某个生产玩具的电子厂生产了一批电子麻雀,他们的飞行距离都是100米,现在用户提出新需求:要求某些麻雀可以飞行150米,200米或者其他距离.
1.抽象组件类,直接看代码:Bird.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public abstract class Bird {
public abstract int fly();
}</span>
2.具体组件类,直接看代码Sparrow.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public class Sparrow extends Bird {
public static final int DISTANCE = 100;
public int fly() {
return DISTANCE;
}
}</span>
3.装饰类,直接看代码DecoratorAbstract.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public abstract class DecoratorAbstract extends Bird {
public Bird bird;
public DecoratorAbstract(Bird bird) {
this.bird = bird;
}
}</span>
4.具体装饰类,直接看代码DecoratorOne,DecoratorTwo.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public class DecoratorOne extends DecoratorAbstract {
public static final int DISTANCE = 50;
DecoratorOne(Bird bird) {
super(bird);
}
public int fly() {
return bird.fly() + DISTANCE;
}
}
</span>
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public class DecoratorTwo extends DecoratorAbstract {
public static final int DISTANCE = 30;
DecoratorTwo(Bird bird) {
super(bird);
}
public int fly() {
return bird.fly() + DISTANCE;
}
}</span>
4.最后看测试类MainTest.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.one;
/**
* @author IluckySi
* @date 20140607
*/
public class MainTest {
public static void main(String[] args) {
Bird birdOne = new Sparrow();
System.out.println("birdOne飞行" + birdOne.fly() +"米");
DecoratorAbstract decoratorOne1 = new DecoratorOne(birdOne);
System.out.println("经过一次装饰后的birdOne飞行" + decoratorOne1.fly() +"米");
DecoratorAbstract decoratorOne2 = new DecoratorOne(decoratorOne1);
System.out.println("经过两次装饰后的birdOne飞行" + decoratorOne2.fly() +"米");
Bird birdTwo = new Sparrow();
System.out.println("birdTwo飞行" + birdTwo.fly() +"米");
DecoratorAbstract decoratorTwo1 = new DecoratorTwo(birdTwo);
System.out.println("经过一次装饰后的birdTwo飞行" + decoratorTwo1.fly() +"米");
DecoratorAbstract decoratorTwo2 = new DecoratorTwo(decoratorTwo1);
System.out.println("经过两次装饰后的birdTwo飞行" + decoratorTwo2.fly() +"米");
}
}
/**
输出结果:
birdOne飞行100米
经过一次装饰后的birdOne飞行150米
经过两次装饰后的birdOne飞行200米
birdTwo飞行100米
经过一次装饰后的birdTwo飞行130米
经过两次装饰后的birdTwo飞行160米
*/</span>
应用场景二:有一个功能是:用户可以通过ReadeWord类的子类ReadEnglishWord读取english.txt文件中的单词.现在有些用户希望同时得到该单词的汉语解释,
同时也有一些用户希望不仅可以得到该单词的汉语解释也能得到该单词的英文例句.前提是:不允许用户修改系统现有的代码和english.txt文件.
1.抽象组件类,直接看代码:ReadWord.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.two;
import java.io.File;
import java.util.ArrayList;
/**
* @author IluckySi
* @date 20140608
*/
public abstract class ReadWord {
public abstract ArrayList<String> readWord(File file);
}</span>
2.具体组件类,直接看代码ReadEnglishWord.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.two;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author IluckySi
* @date 20140608
*/
public class ReadEnglishWord extends ReadWord {
@Override
public ArrayList<String> readWord(File file) {
ArrayList<String> wordList = new ArrayList<String>();
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(file);
br = new BufferedReader(fr);
String line = null;
while((line = br.readLine()) != null) {
wordList.add(line);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(br != null) {
br.close();
br = null;
}
if(fr != null) {
fr.close();
fr = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return wordList;
}
}</span>
3.装饰类,直接看代码DecoratorAbstract
<span style="font-size:12px;">package com.ilucky.pattern.decorator.two;
/**
* @author IluckySi
* @date 20140608
*/
public abstract class DecoratorAbstract extends ReadWord {
public ReadWord readWord;
public DecoratorAbstract(ReadWord readWord) {
this.readWord = readWord;
}
}</span>
4.具体装饰类,直接看代码DecoratorOne.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.two;
import java.io.BufferedReader;
import java.io.File;
import java.io.FileReader;
import java.io.IOException;
import java.util.ArrayList;
/**
* @author IluckySi
* @date 20140608
*/
public class DecoratorOne extends DecoratorAbstract {
public File decoratorFile;
DecoratorOne(ReadWord readWord, File decoreatorFile) {
super(readWord);
this.decoratorFile = decoreatorFile;
}
@Override
public ArrayList<String> readWord(File file) {
ArrayList<String> wordList = readWord.readWord(file);
FileReader fr = null;
BufferedReader br = null;
try {
fr = new FileReader(decoratorFile);
br = new BufferedReader(fr);
String line = null;
int count = 0;
while((line = br.readLine()) != null) {
String word = wordList.get(count).concat("|" + line);
wordList.set(count, word);
count++;
}
} catch (Exception e) {
e.printStackTrace();
} finally {
try {
if(br != null) {
br.close();
br = null;
}
if(fr != null) {
fr.close();
fr = null;
}
} catch (IOException e) {
e.printStackTrace();
}
}
return wordList;
}
}</span>
4.最后看测试类MainTest.
<span style="font-size:12px;">package com.ilucky.pattern.decorator.two;
import java.io.File;
import java.util.ArrayList;
/**
* @author IluckySi
* @date 20140608
*/
public class MainTest {
public static void main(String[] args) {
//系统原来的输出.
ReadWord rew = new ReadEnglishWord();
File englishFile = new File("E:/english.txt");
System.out.println("系统原来的输出:");
ArrayList<String> englishWordList = rew.readWord(englishFile);
for(String word : englishWordList) {
System.out.println(word);
}
//系统添加中文解释装饰后的输出.
System.out.println("系统添加中文解释装饰后的输出:");
File chineseFile = new File("E:/chinese.txt");
DecoratorAbstract decoratorOne = new DecoratorOne(rew, chineseFile);
ArrayList<String> englishWordList2 = decoratorOne.readWord(englishFile);
for(String word : englishWordList2) {
System.out.println(word);
}
//系统添加中文解释装饰和英文例句装饰后的输出.
System.out.println("系统添加中文解释装饰和英文例句装饰后的输出:");
File englishExampleFile = new File("E:/englishExample.txt");
DecoratorAbstract decoratorTwo = new DecoratorOne(decoratorOne, englishExampleFile);
ArrayList<String> englishWordList3 = decoratorTwo.readWord(englishFile);
for(String word : englishWordList3) {
System.out.println(word);
}
}
}
/**
输出结果:
系统原来的输出:
I
am
Ilucky!
系统添加装饰者后的输出:
I|我
am|是
Ilucky!|爱乐客!
系统添加装饰者后的输出:
I|我|I am a teacher!
am|是|I AM a student!
Ilucky!|爱乐客!|I am lucky!
*/</span>
装饰者模式的优点:1.被装饰者和装饰者是松耦合关系,由于装饰仅仅依赖于抽象组件,因此具体装饰只知道他要装饰的对象是抽象组件的某个子类的实例,
但不需要知道是哪一个具体子类.
2.装饰者模式满足"开闭原则",不必修改具体组件,就可以增加新的针对该具体组件的具体装饰.
3.可以使用多个具体装饰装饰具体组件实例.
知识补充:
sun公司在设计java.io包中的类时使用了装饰者模式.
1.java.io包中的InputStream类是一个抽象类,该类的子类和间接子类称作字节输入流.
2.java.io包中的Reader类也是一个抽象类,该类的子类或间接子类称作字符输入流.
下面以Reader为例说明java.io是如何通过装饰者模式来设计类的.
Reader相当于装饰者模式中的抽象组件,FileReader相当于装饰者模式中的具体组件,即被装饰者,而BufferedReader相当于装饰者中的装饰.
需要注意的是:readLine()方法是BufferedReader新增的方法,用户必须使用BufferedReader才能调用该方法.BufferedReader对象在调用read
方法读取文件中的一个字符时,首先委托FileReader对象将字符读入缓存,然后BufferedReader再从缓存中读取字符.BufferedReader对象在使用
readLine()方法读取文件的一行时,首先委托FileReader对象将足够的字符读入缓存,然后BufferedReader对象从缓存中读取一行字符.
即:BufferedReader br = new BufferedReader(new FileReader(new File("E:/a.txt")));另外可以参照源码分析.