プログラミングメモ:Decoratorパターン
- 作者: 株式会社テクノロジック・アート,長瀬嘉秀
- 出版社/メーカー: 翔泳社
- 発売日: 2008/10/22
- メディア: 大型本
- 購入: 5人 クリック: 24回
- この商品を含むブログ (13件) を見る
これを参考にして、JavaでDecoratorを書いた。
(動くかどうかは謎い)
あまり誰かに伝えたいとかではなくてあとで自分が読んで理解できればいいやというスタンスなので、読んでも意味が通じないかもしれない。
Decoratorパターンのメリットは、継承に依らない機能の継ぎ足しができるということらしい。
たとえば上の本で紹介されている例としては、文字列を何がしかに出力する Writer というクラスを、クラスの爆発を避けながら機能追加していくという技ができるようになる。
Writer.java
public interface Writer { public void writeData(List<String> ss); }
Writerを実装し、コンソールに出力するクラスやファイルに出力するクラスを作る。
ConsoleWriter.java
public class ConsoleWriter implements Writer { @Override public void writeData(List<String> ss) { for (String s : ss) {System.out.println(s);} } }
FileWriter.java
public class FileWriter implements Writer { @Override public void writeData(List<String> ss) { Path path = new File("./log.txt").toPath(); try { Files.write(path, ss, Charset.forName("UTF-8"), StandardOpenOption.WRITE); } catch (IOException e) { e.printStackTrace(); } } }
ここまででできた具体的な Writer に後付けで機能を追加したい場合、継承ベースだとそれぞれに対して拡張されたクラスを書かないといけず、それがとてもダルい。
だから Decorator を作る。 Decorator は Writer の操作を持っていて、しかも心の中に Writer を持っていて、 Writer の操作を呼ばれたとき、心の中の Writer を呼び出す。
BRWriter.java
public class BRWriter implements Writer { Writer sink; public BRWriter(Writer sink) { this.sink = sink; } @Override public void writeData(List<String> ss) { List<String> tt = new ArrayList<>(ss); for (String t : tt) { t = new StringBuilder(t).append("<br />").toString(); } sink.writeData(tt); } }
この委譲する性質を使って、クライアントコードからは Decorator をマトリョーシカのように入れ子にしていけば、機能追加されたクラスを自由にお作りすることができる。
Main.java
public class Main { public static void main(String[] args) { Writer out = new BRWriter(new FileWriter()); out.writeData(Arrays.asList(new String[]{"うおーっ", "うおーっ", "うおーっ"})); } }
委譲部分を基底クラスにしておけば、 Decorator も単純になって少しうれしい
AbstraceWriterDecorator.java
public abstract class AbstraceWiterDecorator implements Writer { Writer sink; public AbstraceWiterDecorator(Writer sink) { this.sink = sink; } }
ということらしい。