デザインパターン Composite:容器と中身の同一視

概要

Composite=混合物
ディレクトリとファイルの様な再帰的な構造からなるオブジェクトを生成するパターン

クラス図


本例

抽象

Leaf(葉)

public class File extends Entry {
 private String name;
 private int size;

 public File(String name, int size) {
  this.name = name;
  this.size = size;
 }

 @Override
 public String getName() {
  return this.name;
 }

 @Override
 public int getSize() {
  return this.size;
 }

 @Override
 protected void printList(String prefix) {}
}

Composite(複合体)

public class Directory extends Entry {
 private String name;
 private ArrayList<Entry> directory = new ArrayList<Entry>();

 public Directory(String name) {
  this.name = name;
 }

 public Entry add(Entry entry) {
  this.directory.add(entry);
  return this.toStrong();
 }

 @Override
 public String getName() {
  return this.name;
 }

 @Override
 public int getSize() {
  int size = 0;
  ディレクトリ(ディレクトリ、ファイル)を全件Loop
  Iterator<?> it = this.directory.iterator();
  while (it.hasNext()) {
   Entry entry = (Entry)it.next();
   size += entry.getSize();
  }
  return size;
 }

 @Override
 protected void printList(String prefix) {
  System.out.println(prefix + "/" + this.toString());
  ディレクトリ(ディレクトリorファイル)を全件Loop
  Iterator<?> it = this.directory.iterator();
  while (it.hasNext()) {
   Entry entry = (Entry) it.next();
   entry==ファイル時:親ディレクトリ名と自身の名前を出力
   ※FileクラスのprintList()呼び出し
   entry==ディレクトリ時:親ディレクトリ名と自身の名前を出力
   ※親ディレクトリ名と自身の名前を引数にDirectoryクラスの本メソッドを再帰的に呼び出し

   entry.printList(prefix + "/" + this.name);
  }
 }
}

Component

public class FileTreatmentException extends Exception {

 public FileTreatmentException() {}

 public FileTreatmentException(String msg) {
  super(msg);
 }
}


public abstract class Entry {
 public Entry add(Entry entry) throws FileTreatmentException {
  throw new FileTreatmentException();
 }
 公開メソッド
 public void printList() {
  非公開メソッドを呼び出し
  this.printList("");
 };
 public String toString() {
  return this.getName() + "(" + this.getSize() + ")";
 }
 public abstract String getName();
 public abstract int getSize();
 protected abstract void printList(String prefix);
}

Client(利用者)

public class Main {

 public static void main(String[] args) {
  Directory rootdir = new Directory("root");
  Directory bindir = new Directory("bin");
  Directory tmpdir = new Directory("tmp");
  Directory usrdir = new Directory("usr");
  rootdir.add(bindir);
  rootdir.add(tmpdir);
  rootdir.add(usrdir);
  bindir.add(new File("vi", 10000));
  bindir.add(new File("latex", 20000));
  rootdir.printList();

  System.out.println("");
  Directory java = new Directory("JAVA");
  Directory php = new Directory("PHP");
  Directory c = new Directory("C#");
  usrdir.add(java);
  usrdir.add(php);
  usrdir.add(c);
  java.add(new File("java1.html", 100));
  java.add(new File("java2.java", 200));
  php.add(new File("php1.html", 300));
  php.add(new File("php2.php", 400));
  c.add(new File("c1.c", 500));
  c.add(new File("c2.c", 600));
  rootdir.printList();
 }
}

ディレクトリ構成
root
└bin
 └vi
 └latex
└tmp
└usr
 └JAVA
  └java1.html
  └java2.java
 └PHP
  └php1.html
  └php2.php
 └C#
  └c1.c
  └c2.c


結果
/root(30000)
/root/bin(30000)
/root/tmp(0)
/root/usr(0)

/root(32100)
/root/bin(30000)
/root/tmp(0)
/root/usr(2100)
/root/usr/JAVA(300)
/root/usr/PHP(700)
/root/usr/C#(1100)