[Java] AbstractFactory pattern

4 minute read

What is AbstractFactory pattern?

Create abstract products by combining abstract parts. Pay attention to the interface (API), not to the specific mounting of parts. Then, only the interface (API) is used to assemble the parts and put together the product.

The role of Abstract Product

The AbstractProduct role defines the interface of abstract parts and products created by the AbstractFactory role.

``’’ java package factory;

/**

  • An abstract representation of HTML hyperlinks * */ public abstract class Link extends Item{ // For holding the URL of the link destination protected String url;

public Link(String caption, String url) { super(caption); this.url = url; } }


``'' java
package factory;

import java.io.FileWriter;
import java.io.IOException;
import java.io.Writer;
import java.util.ArrayList;

/**
 * A class that abstractly represents the entire HTML page
 *
 */
public abstract class Page {
protected String title;
protected String author;
protected ArrayList<Item> content = new ArrayList<>();

public Page(String title, String author) {
this.title = title;
this.author = author;
}

public void add(Item item) {
content.add(item);
}

public void output() {
try {
String fileName = title + ".html";
Writer writer = new FileWriter(fileName);
writer.write(this.makeHtml());
writer.close();
System.out.println(fileName + "created.");
} catch (IOException e) {
e.printStackTrace();
}
}
public abstract String makeHtml();
}

``’’ java package factory;

import java.util.ArrayList; /**

  • A class that represents a group of multiple Links and Trays * */ public abstract class Tray extends Item{ protected ArrayList tray = new ArrayList<>();

public Tray(String caption) { super(caption); }

public void add(Item item) { tray.add(item); } }


### The role of Abstract Factory
AbstractFactory role defines the interface for creating an instance of AbstractProduct role.

``'' java
package factory;

/**
 * A class that creates a concrete factory instance by specifying the class name
 *
 */
public abstract class Factory {
public static Factory getFactory(String className) {
Factory factory = null;
try {
factory = (Factory)Class.forName(className).newInstance();
} catch (ClassCastException e) {
System.out.println("Class "+ className + "is not found.");
} catch (Exception e) {
e.printStackTrace();
}
return factory;
}

public abstract Link createLink(String caption, String url);
public abstract Tray createTray(String caption);
public abstract Page createPage(String title, String author);

}

Client (requester) role

The Client role is a role that performs work using only the interfaces of Abstract Factory and Abstract Product. The Client role does not know about specific parts, products, or factories.

``’’ java import factory.Factory; import factory.Link; import factory.Page; import factory.Tray;

public class Main {

public static void main(String[] args) {

if (args.length != 1) { System.out.println(“Usage: java Main class.mame.of.ConcreateFactory”); System.out.println(“Example 1: java Main listfactory,ListFactory”); System.out.println(“Example 2: java Main tablefactory,TableFactory”); System.exit(0); }

Factory factory = Factory.getFactory(args[0]);

Link asahi = factory.createLink(“Asahi Shimbun”, “http://www.asahi.com/”); Link yomiuri = factory.createLink(“Yomiuri Shimbun”, “http://www.yomiuri.co.jp/”);

Link usYahoo = factory.createLink(“Yahoo!”, “http://www.yahoo.com/”); Link jpYahoo = factory.createLink(“Yahoo!Japan”, “http://www.yahoo.co.jp”); Link excite = factory.createLink(“Excite”, “http://www.excite.com/”); Link google = factory.createLink(“Google”, “http://www.google.com/”);

Tray trayNews = factory.createTray(“newspaper”); trayNews.add(asahi); trayNews.add(yomiuri);

Tray trayYahoo = factory.createTray(“Yahoo!”); trayYahoo.add(usYahoo); trayYahoo.add(jpYahoo);

Tray traySearch = factory.createTray(“search engine”); traySearch.add(trayYahoo); traySearch.add(excite); traySearch.add(google);

Page page = factory.createPage(“LinkPage”, “Taro Tanaka”); page.add(trayNews); page.add(traySearch); page.output(); }

}


### The role of Concrete Product
In the role of Conctete Product, implement the interface (API) of the role of Abstract.

``'' java
package listFactory;

import factory.Link;

public class ListLink extends Link{

public ListLink(String caption, String url) {
super(caption, url);
}

public String makeHtml() {
return "<li><a href=\"" + url + "\">" + caption + "</a></li>\n";
}

}

``’’ java package listFactory;

import java.util.Iterator;

import factory.Item; import factory.Page;

public class ListPage extends Page{

public ListPage(String title, String author) { super(title, author); }

@Override public String makeHtml() { StringBuffer buffer = new StringBuffer(); buffer.append(“<html><head>" + title + "</head>\n”); buffer.append(“<body>\n”); buffer.append(“<h1>” + title + “</h1>\n”); buffer.append(“<ul>\n”); Iterator it = content.iterator(); while (it.hasNext()) { Item item = it.next(); buffer.append(item.makeHtml()); } buffer.append("</ul>\n"); buffer.append("<hr><address>" + author + "</address>"); buffer.append("</body></html>\n"); return buffer.toString(); } }


``'' java
package listFactory;

import java.util.Iterator;

import factory.Item;
import factory.Tray;

public class ListTray extends Tray {public ListTray(String caption) {
  super(caption);
 }

 public String makeHtml() {
  StringBuffer buffer = new StringBuffer();
  buffer.append("<li>\n");
  buffer.append(caption + "\n");
  buffer.append("<ul>\n");
  Iterator<Item> it = tray.iterator();
  while (it.hasNext()) {
   Item item = it.next();
   buffer.append(item.makeHtml());
  }
  buffer.append("</ul>\n");
  buffer.append("</li>\n");
  return buffer.toString();
 }
}

ConcreteFactory(具体的な工場)の役

ConcreteFactory役ではAbstractFactory役のインターフェース(API)を定める。

package listFactory;

import factory.Factory;
import factory.Link;
import factory.Page;
import factory.Tray;

public class ListFactory extends Factory {

 @Override
 public Link createLink(String caption, String url) {
  return new ListLink(caption, url);
 }

 @Override
 public Tray createTray(String caption) {
  return new ListTray(caption);
 }

 @Override
 public Page createPage(String title, String author) {
  return new ListPage(title, author);
 }
}

引数でtableFactory.TableFactoryを渡して実行して作成されたhtmlファイル

スクリーンショット 2020-09-04 15.50.31.png

別の具体的な工場を追加する

工場を追加するのは簡単であった。 どのようなクラスを作り、どのようなメソッドを実装すれば良いかが明確なため。

package tableFactory;

import factory.Link;

public class TableLink extends Link {

 public TableLink(String caption, String url) {
  super(caption, url);
 }

 @Override
 public String makeHtml() {
  return "<td><a href=\"" + url + "\">" + caption + "</a></td>\n";
 }
}
package tableFactory;

import java.util.Iterator;

import factory.Item;
import factory.Page;

public class TablePage extends Page {

 public TablePage(String title, String author) {
  super(title, author);
 }

 @Override
 public String makeHtml() {
  StringBuffer buffer = new StringBuffer();
  buffer.append("<html><head><title>" + title + "</title></head>\n");
  buffer.append("<body>\n");
  buffer.append("<h1>" + title + "</h1>\n");
  buffer.append("<table width=\"80%\" border=\"3\">\n");
  Iterator<Item> it = content.iterator();
  while (it.hasNext()) {
   Item item = it.next();
   buffer.append("<tr>" + item.makeHtml() + "</tr>");
  }
  buffer.append("</table>\n");
  buffer.append("<hr><address>" + author + "</address>");
  buffer.append("</body></html>\n");
  return buffer.toString();
 }
}
package tableFactory;

import java.util.Iterator;

import factory.Item;
import factory.Tray;

public class TableTray extends Tray {

 public TableTray(String caption) {
  super(caption);
 }

 @Override
 public String makeHtml() {
  StringBuffer buffer = new StringBuffer();
  buffer.append("<td>");
  buffer.append("<table width=\"100%\" border=\"1\"><tr>");
  buffer.append("<td bgcolor=\"#cccccc\" align=\"center\" colspan=\"" + tray.size() + "\"><b>" + caption + "</b></td>");
  buffer.append("</tr>\n");
  buffer.append("<tr>\n");
  Iterator<Item> it = tray.iterator();
  while (it.hasNext()) {
   Item item = it.next();
   buffer.append(item.makeHtml());
  }
  buffer.append("</tr></table>");
  buffer.append("</td>");
  return buffer.toString();
 }
}
package tableFactory;

import factory.Factory;
import factory.Link;
import factory.Page;
import factory.Tray;

public class TableFactory extends Factory {

 @Override
 public Link createLink(String caption, String url) {
  return new TableLink(caption, url);
 }

 @Override
 public Tray createTray(String caption) {
  return new TableTray(caption);
 }

 @Override
 public Page createPage(String title, String author) {
  return new TablePage(title, author);
 }
}

Client役であるMainは全く変更せず、実行時の引数をtableFactory.TableFactoryにして実行して作成されたhtmlファイル

スクリーンショット 2020-09-04 15.57.57.png

https://github.com/aki0207/abstractFactory

こちらを参考にさせていただきました。 増補改訂版Java言語で学ぶデザインパターン入門

Tags:

Updated: