装饰者模式与其在Java API中的运用

ThanhColon 8年前
   <h3>一、装饰者模式简介</h3>    <p>装饰者模式,是面向对象编程领域中,一种动态地往一个类中添加新的行为的设计模式。就功能而言,装饰者模式相比生成子类更为灵活,这样可以给某个对象而不是整个类添加一些功能。</p>    <p>1.基本原理</p>    <p>通过使用装饰者模式,可以在运行时扩充一个类的功能。原理是:增加一个装饰类包裹原来的类,包裹的方式一般是通过在将原来的对象作为修饰类的构造函数的参数。装饰类实现新的功能,但是,在不需要用到新功能的地方,它可以直接调用原来的类中的方法。装饰类必须和原来的类有相同的接口。</p>    <p>装饰者模式是类继承的另外一种选择。类继承在编译时候增加行为,而装饰者模式是在运行时增加行为。</p>    <p>当有几个相互独立的功能需要扩充时,这个区别就变得很重要。在有些面向对象的编程语言中,类不能在运行时被创建,通常在设计的时候也不能预测到有哪几种功能组合。这就意味着要为每一种组合创建一个新类。相反,装饰者模式是面向运行时候的对象实例的,这样就可以在运行时根据需要进行组合。一个装饰者模式的示例是JAVA里的 <strong> <em>Java I/O Streams</em> </strong> 的实现。</p>    <p>装饰者模式的UML类图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/e23ef37ce1f947367c26a04e9ba1784d.png"></p>    <p>2.示例代码</p>    <p>以 <strong> <em>砂锅羊肉面</em> </strong> 为实例,别问为什么,(╯°□°)╯︵┻━┻</p>    <p>Component相当于Marmite(砂锅)类:</p>    <pre>  <code class="language-java">public abstract class Marmite {      String description = "砂锅";        public String getDescription() {          return description;      }        public abstract Integer cost();        @Override      public String toString() {          return "这是一碗:" + getDescription() + ",价格:" + cost() + "元";      }  }</code></pre>    <p>ConcreteComponent是NoddlesMarmite(砂锅面条)类:</p>    <pre>  <code class="language-java">public class NoddlesMarmite extends Marmite {        public NoddlesMarmite() {          description = "砂锅面条";      }        public Integer cost() {          return 8;      }  }</code></pre>    <p>Decorator是MaterialDecorator</p>    <pre>  <code class="language-java">public abstract class MaterialDecorator extends Marmite {      public abstract String getDescription();  }</code></pre>    <p>ConcreteDecorator是MuttonMarmite:</p>    <pre>  <code class="language-java">public class MuttonMarmite extends MaterialDecorator {      Marmite marmite;        public MuttonMarmite(Marmite marmite) {          this.marmite = marmite;      }        @Override      public String getDescription() {          return "羊肉、" + marmite.getDescription();      }        @Override      public Integer cost() {          return 5 + marmite.cost();      }  }</code></pre>    <p>这是测试代码:</p>    <pre>  <code class="language-java">public class MarmiteTest {      public static void main(String[] args) {          Marmite marmiteNoddle = new NoddlesMarmite();          System.out.println(marmiteNoddle.toString());          Marmite muttonMarmiteNoddle = new MuttonMarmite(marmiteNoddle);          System.out.println(muttonMarmiteNoddle.toString());      }  }</code></pre>    <h3>二、Java API中装饰者的运用</h3>    <p>先看一段demo</p>    <pre>  <code class="language-java">public class JavaDemo {      public static void main(String[] args) {          System.out.println("请输入一句话:");          BufferedInputStream bufferedInputStream = new BufferedInputStream(System.in);          String msg = "wocao";          try {              BufferedReader bufferedReader=new BufferedReader(new InputStreamReader(bufferedInputStream));              msg = bufferedReader.readLine();          } catch (Exception e){              e.printStackTrace();          }          System.out.println("输入的是:" + msg);      }  }</code></pre>    <p>这段代码的功能是将控制台中输入的内容打印出来。</p>    <p>查看 <strong> <em>java api</em> </strong> 得知</p>    <p>BufferedInputStream继承的是FilterInputStream,如下图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/b5712cfb88f9cdbb3826ca412d766450.jpg"></p>    <p>FilterInputStream继承的是InputStream,并且有InputStream对象的一个引用</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/4fc9a79b528eaf683b5649d1f6ba3346.jpg"></p>    <p>由此可以得出</p>    <p>InputStream相当于Component,FileterInputStream相当于Decorator,BufferedInputStream相当于ConcreteDecorator,System.in相当于ConcreteComponent。</p>    <h3>三、自己实现一个关于InputStream的ConcreteDecorator</h3>    <p>talk is cheap, show me the code</p>    <pre>  <code class="language-java">public class LowerCaseInputStream extends FilterInputStream {        public LowerCaseInputStream(InputStream in){          super(in);      }        @Override      public int read() throws IOException {          int c=super.read();          return (c==-1?c:Character.toLowerCase((char)c));      }        @Override      public int read(byte[] b, int off, int len) throws IOException {          int result=super.read(b,off,len);          for(int i=off;i<off+result;i++){              b[i]=(byte)Character.toLowerCase((char)b[i]);          }          return result;      }  }</code></pre>    <p>不想解释了,心累</p>    <p>看不懂的,送你一幅图:</p>    <p style="text-align:center"><img src="https://simg.open-open.com/show/6f250094c212044197f0d775f2df816b.jpg"></p>    <p>---------------------------------------EOF--------------------------------------</p>    <p>参考资料:</p>    <ul>     <li> <p><a href="/misc/goto?guid=4959736852367967183" rel="nofollow,noindex">https://zh.wikipedia.org/wiki...</a></p> </li>     <li> <p>Head First设计模式</p> </li>    </ul>    <p> </p>    <p>来自:https://segmentfault.com/a/1190000008305233</p>    <p> </p>