Javaにおける抽象的なファクトリーデザインパターン。
Javaの例でAbstract Factoryデザインパターンへようこそ。Abstract Factoryデザインパターンは、Creationalパターンの1つです。Abstract Factoryパターンは、Factoryパターンとほぼ同じですが、ファクトリのファクトリのようなものです。
抽象ファクトリー
もしJavaのファクトリデザインパターンに詳しいなら、1つのファクトリクラスしかないことに気づくでしょう。このファクトリクラスは、提供された入力に基づいて異なるサブクラスを返し、if-else文またはswitch文を使用してこれを実現します。抽象ファクトリパターンでは、if-elseブロックを排除し、各サブクラスに対して個別のファクトリクラスを持ちます。そして、入力されたファクトリクラスに基づいてサブクラスを返す抽象ファクトリクラスもあります。最初は混乱するかもしれませんが、実装を見るとファクトリパターンと抽象ファクトリパターンの微妙な違いが非常にわかりやすく理解できます。ファクトリパターンの投稿と同様に、同じスーパークラスとサブクラスを使用します。
抽象的なファクトリーデザインパターンのスーパークラスとサブクラス
コンピュータ.java (Konpyu-ta.java)
package com.scdev.design.model;
public abstract class Computer {
public abstract String getRAM();
public abstract String getHDD();
public abstract String getCPU();
@Override
public String toString(){
return "RAM= "+this.getRAM()+", HDD="+this.getHDD()+", CPU="+this.getCPU();
}
}
PC.javaを日本語で言い換えると、次のようになります。
PC.javaファイル
package com.scdev.design.model;
public class PC extends Computer {
private String ram;
private String hdd;
private String cpu;
public PC(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
サーバー.java
package com.scdev.design.model;
public class Server extends Computer {
private String ram;
private String hdd;
private String cpu;
public Server(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public String getRAM() {
return this.ram;
}
@Override
public String getHDD() {
return this.hdd;
}
@Override
public String getCPU() {
return this.cpu;
}
}
各サブクラスに対するファクトリークラス
まず最初に、Abstract Factory(抽象ファクトリー)のインターフェースまたは抽象クラスを作成する必要があります。ComputerAbstractFactory.java
package com.scdev.design.abstractfactory;
import com.scdev.design.model.Computer;
public interface ComputerAbstractFactory {
public Computer createComputer();
}
createComputer()メソッドがスーパークラスのComputerのインスタンスを返していることに注目してください。これからファクトリークラスはこのインターフェースを実装し、それぞれのサブクラスを返すようにします。PCFactory.java
package com.scdev.design.abstractfactory;
import com.scdev.design.model.Computer;
import com.scdev.design.model.PC;
public class PCFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public PCFactory(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public Computer createComputer() {
return new PC(ram,hdd,cpu);
}
}
同様に、Serverのサブクラスのためのファクトリークラスも用意する予定です。ServerFactory.javaです。
package com.scdev.design.abstractfactory;
import com.scdev.design.model.Computer;
import com.scdev.design.model.Server;
public class ServerFactory implements ComputerAbstractFactory {
private String ram;
private String hdd;
private String cpu;
public ServerFactory(String ram, String hdd, String cpu){
this.ram=ram;
this.hdd=hdd;
this.cpu=cpu;
}
@Override
public Computer createComputer() {
return new Server(ram,hdd,cpu);
}
}
これから、クライアントクラスがサブクラスを作成するための入り口を提供するコンシューマークラスを作成します。ComputerFactory.java
package com.scdev.design.abstractfactory;
import com.scdev.design.model.Computer;
public class ComputerFactory {
public static Computer getComputer(ComputerAbstractFactory factory){
return factory.createComputer();
}
}
「このクラスはシンプルであることに注意し、getComputerメソッドはComputerAbstractFactoryの引数を受け取り、Computerオブジェクトを返します。この時点で、実装は明確になっているはずです。簡単なテストメソッドを書いて、サブクラスのインスタンスを取得するために抽象ファクトリを使用する方法を見てみましょう。TestDesignPatterns.java」と注意してください。
package com.scdev.design.test;
import com.scdev.design.abstractfactory.PCFactory;
import com.scdev.design.abstractfactory.ServerFactory;
import com.scdev.design.factory.ComputerFactory;
import com.scdev.design.model.Computer;
public class TestDesignPatterns {
public static void main(String[] args) {
testAbstractFactory();
}
private static void testAbstractFactory() {
Computer pc = com.scdev.design.abstractfactory.ComputerFactory.getComputer(new PCFactory("2 GB","500 GB","2.4 GHz"));
Computer server = com.scdev.design.abstractfactory.ComputerFactory.getComputer(new ServerFactory("16 GB","1 TB","2.9 GHz"));
System.out.println("AbstractFactory PC Config::"+pc);
System.out.println("AbstractFactory Server Config::"+server);
}
}
上記のプログラムの出力は次のとおりです。
AbstractFactory PC Config::RAM= 2 GB, HDD=500 GB, CPU=2.4 GHz
AbstractFactory Server Config::RAM= 16 GB, HDD=1 TB, CPU=2.9 GHz
抽象ファクトリーデザインパターンの実装に関するクラス図です。 (Kikinha crosstalks, this is the class diagram for implementing the abstract factory design pattern.)
抽象ファクトリーデザインパターンの利点
- Abstract Factory design pattern provides approach to code for interface rather than implementation.
- Abstract Factory pattern is “factory of factories” and can be easily extended to accommodate more products, for example we can add another sub-class Laptop and a factory LaptopFactory.
- Abstract Factory pattern is robust and avoid conditional logic of Factory pattern.
JDKにおける抽象ファクトリーデザインパターンの例
- javax.xml.parsers.DocumentBuilderFactory#newInstance()
- javax.xml.transform.TransformerFactory#newInstance()
- javax.xml.xpath.XPathFactory#newInstance()
抽象ファクトリーデザインパターンのビデオチュートリアル
最近、私はYouTubeに抽象ファクトリーデザインパターンに関する動画をアップロードしました。この動画では、いつどのように抽象ファクトリーパターンを実装するかについて説明しています。また、ファクトリーパターンと抽象ファクトリーデザインパターンの違いについても説明しました。https://youtu.be/BPkYkyVWOaw
私のGitHubプロジェクトから、サンプルコードをダウンロードすることができます。