浅谈装饰模式
装饰与继承的区别:
装饰:基于已有的功能,并提供加强功能,装饰类通常会通过构造方法接收被装饰的对象。并基于被装饰的对象的功能,提供更强的功能。相对于继承来说装饰模式可以在不使用创造更多子类的情况下,将对象的功能加以扩展。英文叫:Decorator
继承:因为要扩展某个功能,就得继承父类,然后覆盖重写,导致这个体系更加臃肿,并且内存占用高。
一般情况下,其实接口也可以当做一种抽象类来看待,也就是说父类对象也可以是接口,如果一个类A实现了一个接口T,当我们在声明实例:T t =new A();时,t看起来是一个T,本质上是一个A,这也是多态的一种!
验证一下,首先先创建一个接口a:
1 public class test { 2 interface a{ 3 void fun(); 4 } 5 class b implements a{ 6 7 public void fun() { 8 System.out.println("这个实现接口类!"); 9 } 10 11 } 12 class c extends b{ 13 public void fun(){ 14 System.out.println("这是实现接口类的子类!!"); 15 } 16 } 17 public static void main(String[] args) { 18 a dd = new test().new c(); 19 dd.fun(); 20 } 21 }
运行:
例1:
摘自CSDN的一位大神的例子,看这个程序只要多态的功能理清楚也就明白了,说白了装饰模式无非就是多态与构造方法的灵活运用罢了:
1 public class decorateMode{ 2 //定义被装饰者 3 public interface Human { 4 public void wearClothes(); 5 6 public void walkToWhere(); 7 } 8 9 //定义装饰者 10 public abstract class Decorator implements Human { 11 private Human human; 12 13 public Decorator(Human human) { 14 this.human = human; 15 } 16 17 public void wearClothes() { 18 human.wearClothes(); 19 } 20 21 public void walkToWhere() { 22 human.walkToWhere(); 23 } 24 } 25 26 //下面定义三种装饰,这是第一个,第二个第三个功能依次细化,即装饰者的功能越来越多 27 public class Decorator_zero extends Decorator { 28 29 public Decorator_zero(Human human) { 30 super(human); 31 } 32 33 public void goHome() { 34 System.out.println("进房子。。"); 35 } 36 37 public void findMap() { 38 System.out.println("书房找找Map。。"); 39 } 40 41 public void wearClothes() { 42 // TODO Auto-generated method stub 43 super.wearClothes(); 44 goHome(); 45 } 46 47 public void walkToWhere() { 48 // TODO Auto-generated method stub 49 super.walkToWhere(); 50 findMap(); 51 } 52 } 53 54 public class Decorator_first extends Decorator { 55 56 public Decorator_first(Human human) { 57 super(human); 58 } 59 60 public void goClothespress() { 61 System.out.println("去衣柜找找看。。"); 62 } 63 64 public void findPlaceOnMap() { 65 System.out.println("在Map上找找。。"); 66 } 67 68 public void wearClothes() { 69 // TODO Auto-generated method stub 70 super.wearClothes(); 71 goClothespress(); 72 } 73 74 public void walkToWhere() { 75 // TODO Auto-generated method stub 76 super.walkToWhere(); 77 findPlaceOnMap(); 78 } 79 } 80 81 public class Decorator_two extends Decorator { 82 83 public Decorator_two(Human human) { 84 super(human); 85 } 86 87 public void findClothes() { 88 System.out.println("找到一件D&G。。"); 89 } 90 91 public void findTheTarget() { 92 System.out.println("在Map上找到神秘花园和城堡。。"); 93 } 94 95 public void wearClothes() { 96 // TODO Auto-generated method stub 97 super.wearClothes(); 98 findClothes(); 99 } 100 101 public void walkToWhere() { 102 // TODO Auto-generated method stub 103 super.walkToWhere(); 104 findTheTarget(); 105 } 106 } 107 108 //定义被装饰者,被装饰者初始状态有些自己的装饰 109 public class Person implements Human { 110 111 public void wearClothes() { 112 // TODO Auto-generated method stub 113 System.out.println("穿什么呢。。"); 114 } 115 116 public void walkToWhere() { 117 // TODO Auto-generated method stub 118 System.out.println("去哪里呢。。"); 119 } 120 } 121 //测试类,看一下你就会发现,跟java的I/O操作有多么相似 122 public static void main(String[] args) { 123 decorateMode decorateMode=new decorateMode(); 124 Human person =decorateMode. new Person(); 125 Decorator decorator = decorateMode.new Decorator_two(decorateMode.new Decorator_first( 126 decorateMode.new Decorator_zero(person))); 127 decorator.wearClothes(); 128 decorator.walkToWhere(); 129 } 130 }
运行结果:
例2:
读取文件的行内容,并给每行前加上行数、行后加上分号
1 package com.beiwo.Io; 2 3 import java.io.BufferedReader; 4 import java.io.FileNotFoundException; 5 import java.io.FileReader; 6 import java.io.IOException; 7 import java.io.Reader; 8 9 /* 10 11 BufferedReader : 拓展FileReader的功能。 12 13 需求1 :实现通过readLine读取代码 ,每一行加上一个行号。 14 需求2 :实现通过readLine读取代码 ,每一行加上一个分号。 15 需求3 :实现通过readLine读取代码 ,每一行加上一个引号。 16 17 //========================================================= 18 需求4 :实现通过readLine读取代码 ,每一行加上一个引号 + 行号。 19 需求5 :实现通过readLine读取代码 ,每一行加上一个分号 + 行号。 20 需求6 :实现通过readLine读取代码 ,每一行加上一个分号 + 引号。 21 需求7 :实现通过readLine读取代码 ,每一行加上一个分号 + 引号 + 行号。 22 23 如果用继承: 24 好处:代码结构和清晰容易理解 25 缺点:继承体系会很庞大。实现七个需求就得创建七个子类 26 27 28 装饰者模式 : 增强一个类的功能还可以让装饰者类之间互相装饰。 29 30 31 32 */ 33 34 //添加行号 35 class BufferedReaderLineNum extends BufferedReader{ 36 //定义一个对象来接收传进来的对象 37 BufferedReader bufferedReader; 38 int count = 1; 39 40 //子类继承父类会默认调用父类的无参构造方法 41 public BufferedReaderLineNum (BufferedReader in) { 42 super(in); 43 this.bufferedReader = in; 44 } 45 46 //复写readLine方法 47 @Override 48 public String readLine() throws IOException { 49 // TODO Auto-generated method stub 50 //调用父类的readLine 51 String content = bufferedReader.readLine(); 52 //给内容田间一个行号 53 if(content == null){ 54 55 return null; 56 } 57 content = count+" "+content; 58 count++; 59 return content; 60 } 61 62 } 63 64 //添加分号的 65 class BufferedReaderLineSemi extends BufferedReader{ 66 //定义一个对象来接收传进来的对象 67 BufferedReader bufferedReader; 68 //子类继承父类会默认调用父类的无参构造方法 69 public BufferedReaderLineSemi (BufferedReader in) { 70 super(in); 71 this.bufferedReader = in; 72 } 73 74 //复写(重写)readLine方法 75 @Override 76 public String readLine() throws IOException { 77 // TODO Auto-generated method stub 78 //调用父类的readLine 79 String content = bufferedReader.readLine(); 80 //给内容田间一个行号 81 if(content == null){//表示数据已经读完 82 83 return null; 84 } 85 86 return content+";"; 87 } 88 89 } 90 91 92 93 public class Demo1 { 94 95 /** 96 * @param args 97 * @throws IOException 98 */ 99 public static void main(String[] args) throws IOException { 100 // TODO Auto-generated method stub 101 testLineNum(); 102 } 103 104 public static void testLineNum () throws IOException{ 105 106 //1.开启一个通道,并且带一个文件路径 107 FileReader reader = new FileReader("这里填上文件路径如:C:\\a.java"); 108 //创建缓冲流 109 BufferedReader bufferedReader = new BufferedReader(reader); 110 //2.创建一个带分号的缓冲流 111 BufferedReaderLineSemi lineSemi = new BufferedReaderLineSemi(bufferedReader); 112 //创建一个缓冲流 ,带行号加分号 113 BufferedReaderLineNum lineNum = new BufferedReaderLineNum(lineSemi); 114 //3.开始读取数据 115 String content = null; 116 while((content = lineNum.readLine())!=null){ 117 118 System.out.println(content); 119 } 120 121 //4.关闭资源 122 lineNum.close(); 123 } 124 }
效果: