Welcome 微信登录

首页 / 操作系统 / Linux / Java 的设计模式之一装饰者模式

刚开始接触装饰者的设计模式,感觉挺难理解的,不够后来花了一个晚上的时间,终于有头绪了装饰者设计模式:如果想对已经存在的对象进行装饰,那么就定义一个类,在类中对已经有的对象进行功能的增强或添加另外的行为,这个类就叫装饰者类。被修饰的类叫被装饰者类,是已经存在有的功能。在装饰者类之间又可以互相装饰特点:
          1.装饰类通过构造方法来接收被装饰者的对象,调用它里面的功能或行为
          2. 基于对被装饰对象的功能进行扩展,提供更强大的功能Java中的IO流是典型的装饰者模式下面来看一行简短的代码:扩展一个接口,定义一个抽象的方法,这个接口实际上就是一个被装饰者类interface Work {public void work();}画画类:class Drawing implements Work { //实现接口@Overridepublic void work() {//必须实现接口中的方法// TODO Auto-generated method stubSystem.out.println("画画");}}上色类:class Colour implements Work {Work w;//在内部维护一个被装饰的类public Colour(Work w) {this.w = w;}@Overridepublic void work() {w.work();System.out.println("给画上色");}}装裱类:class Mounting implements Work {Work w;//在内部维护一个被装饰的类public Mounting(Work w) {this.w = w;}@Overridepublic void work() {w.work();System.out.println("给画装裱");}}测试类:public class Test {public static void main(String[] args) throws FileNotFoundException {Work w = new Drawing();Colour c = new Colour(w);Mounting m = new Mounting(c);m.work();}} 上面是一个简单的装饰者模式。装饰者模式的设计原则:
       1.多用组合,少用继承
      继承的子类实现父类的行为,是在编译时静态决定的,而且继承的行为是相同的,但是利用装饰者之间的相互修饰(组合)
    就可以扩展出强大的功能,可以动态的进行扩展,也可以撤销
  2.对扩展开放,对修改关闭
      扩展是在继承的前提下实现,在子类中修改。扩展是在继承被装饰者类实现行为或功能,不需要修改装饰者的类,只是在此基础 上,装饰另外的功能或行为需求:定义一个人吃面,可以加生菜,也可以加辣椒,也可以都加EatNoodle类:class EatNoodle {public void eat() {System.out.print("吃面");}}装饰者类class SunEatNoodle1 {EatNoodle eatNd;public SunEatNoodle1(EatNoodle eatNd) {//定义构造方法来接收被装饰者的对象this.eatNd = eatNd;}public void eat() {eatNd.eat();System.out.println("加点香菜,感觉好吃");}}装饰者之间的相互修饰class SunEatNoodle2 {//EatNoodle eatNd;SunEatNoodle1 sunEat1;public SunEatNoodle2( SunEatNoodle1 sunEat1) { //定义构造方法来接收装饰者的对象//this.eatNd = eatNd;this.sunEat1 = sunEat1;}public void eat() {System.out.println();//eatNd.eat();sunEat1.eat();System.out.println("再来点辣椒,就更好吃了");}}测试类:public class Demo1 {public static void main(String[] args) {EatNoodle eatNoodle = new EatNoodle();//eatNoodle.eat();SunEatNoodle1 sunEat1 = new SunEatNoodle1(eatNoodle);sunEat1.eat();SunEatNoodle2 sunEat2 = new SunEatNoodle2(sunEat1);//装饰者类之间的相互修饰sunEat2.eat();}}运行结果:装饰者与继承的关系在添加 不同功能的时候。我们会想到了用继承来实现。而且刚学装饰者模式的时候,觉得挺难理解的,装饰者的前世今生就是继承。那为什么不用继承呢?这样岂不是更容易理解,用起来也挺方便。下面通过一个简单的Demo做一下比较。需求:用继承来实现通过readLine读取代码  ,每一行加上一个行号和分号的功能//1.添加行号,默认继承BufferedReaderclass BufferedReaderLineNum extends BufferedReader {int count = 0;public BufferedReaderLineNum(BufferedReader in) { //Reader:默认创建一个目标文件的缓冲字符输入流的大小 super(in);}@Override//3.重写父类的readLine方法public String readLine() throws IOException {String countent = super.readLine();//调用父类默认的行号if (countent == null) {return null;}//System.out.println(count + " " + countent);count++;return count + " " + countent;}}//添加分号class BufferedReaderSemicolon extends BufferedReader {
BufferedReader reader;public BufferedReaderSemicolon(BufferedReader in) {//Reader:默认创建一个目标文件的缓冲字符输入流的大小 super(in);this.reader = in;}@Override//3.重写父类的readLine方法public String readLine() throws IOException {String countent = reader.readLine();if (countent == null) {//判断数据已经读完return null;}return countent + ";";}}public class Demo1 {public static void main(String[] args) throws IOException {//FileReader用于字符输入流,FileInputStream是用字节输入流//1.创建通道,拿到一个指定的目标文件FileReader fileRead = new FileReader("C:\java\decorator\Test.java");BufferedReader reader = new BufferedReader(fileRead);//2.创建行号的缓冲流BufferedReaderLineNum readerLineNum = new BufferedReaderLineNum(reader);//.创建分号的缓冲流BufferedReaderSemicolon readerSemicolon = new BufferedReaderSemicolon(readerLineNum);String content = null;//使用readLine(),包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 nullwhile((content = readerSemicolon.readLine()) != null) {System.out.println(content);}//4.关闭资源readerLineNum.close();}} 然后再通过装饰者模式来实现上面的功能://添加行号class BufferederReadLineNum extends BufferedReader {BufferedReader bufferedReader;//1.内部维护的被装饰者的类int count = 1;public BufferederReadLineNum(BufferedReader read) {super(read);//如果没有这行代码,会显示编译报错,显示没有隐式性的给这个构造函数定义this.bufferedReader = read;}@Overridepublic String readLine() throws IOException {String countent = bufferedReader.readLine();if(countent == null) {return null;}countent = count + " " + countent;count++;return countent;}}//2.添加分号class BufferedReaderSemicolon1 extends BufferedReader {BufferedReader bufferedReader;//1.内部维护的被装饰者的类public BufferedReaderSemicolon1(BufferedReader read) { super(read);this.bufferedReader = read;}@Override//3.重写父类的readLine方法public String readLine() throws IOException {String countent = super.readLine();//调用父类默认的行号if (countent == null) { //判断数据已经读完return null;}return countent + ";";}}public class Test2 {public static void main(String[] args) throws IOException {//1.创建通道,拿到一个指定的目标文件FileReader fileRead = new FileReader("C:\java\代码\src\Test.java");//2.创建缓冲区 BufferedReader bufferedReader = new BufferedReader(fileRead);//3创建分号的缓冲流BufferedReaderSemicolon1 readerSemicolon = new BufferedReaderSemicolon1(bufferedReader);//创建行号的缓冲流在装饰者创建的BufferederReadLineNum readerLineNum = new BufferederReadLineNum(readerSemicolon);//4.读取数据String content = null;//使用readLine(),包含该行内容的字符串,不包含任何行终止符,如果已到达流末尾,则返回 nullwhile((content = readerLineNum.readLine()) != null) {System.out.println(content);}//5.关闭资源readerLineNum.close();}}通过上面的代码,可能不能完全看出使用装饰者模式的强大功能,你可以在多创建几个类,添加多个功能,结果就显而易见了。在实现多个功能的时候,使用继承的体系会过于庞大,显得很臃肿。使用了装饰者来进行动态性的添加一些附加功能,确保在运行时,不用改变该对象的结构就可以在外部添加附加的功能。通常也是通过继承来实现给定类的功能扩展来实现更强大的功能。提高了代码的可维护性和简洁性。本文永久更新链接地址:http://www.linuxidc.com/Linux/2016-12/138366.htm