メインコンテンツへ移動

デザインパターン:ファクトリパターン(Factory Pattern)

無料2015-03-06#Design_Pattern#工厂模式#工厂方法模式#抽象工厂模式#Factory Pattern

以前は XXXFactory クラスを定義して new オブジェクトを作成するのがファクトリパターンだと思っていました。しかも便宜上、ファクトリクラスの Create メソッドを static メソッドとして定義することが一般的でした。しかし、詳しく学んだ後、ファクトリパターンはそれほど単純なものではなく、厳密に言えば「シンプルファクトリパターン」と呼ばれるこの方法は「パターン」とはみなせないことに気づきました。

no_mkd

一.ファクトリパターンとは?

1.「シンプルファクトリパターン」、Simple Factory Pattern

つまり、Factory クラスでオブジェクトを new する静的ファクトリメソッドを定義する一般的な方法です。要約で「厳密に言えば、『シンプルファクトリパターン』と呼ばれるこの方法は『パターン』とはみなせない」と述べましたが、静的ファクトリメソッドは本当の「デザインパターン」ではありませんが、この方法の応用も広く、いくつかのメリットをもたらすため、『デザインパターン』ではないからといって捨てるべきではありません

2.ファクトリメソッドパターン、Factory Method Pattern

ファクトリパターンの核心です。抽象的な「ファクトリメソッド」を定義してオブジェクトを new し、そのクラスの拡張クラスが new のプロセスを実装します。

この方法は、オブジェクト生成プロセスとオブジェクトの振る舞いを分離します(詳しくは説明しません)。正確には、オブジェクト生成を「下放」します(ここでの動詞に注意——「下放」)。

3.抽象ファクトリパターン、Abstract Factory Pattern

ファクトリメソッドパターンの応用と拡張です。複数の「ファクトリメソッド」を抽象ファクトリクラスにカプセル化し、「一組のオブジェクトを new する」目的を達成します。

二.一般的な方法(ファクトリパターンを使用しない)

服を売る小店舗を開くとしましょう。まず、ColthesStore クラスが注文を受け付けて完成した服を返す必要があります。ClothesStore クラスは Clothes クラスに依存する必要があります。結局のところ、操作する具体的なオブジェクトは Clothes だからです。ClothesStore には服を作る工程(製作、装飾加工など)も必要です。では、ClothesStore は以下のようになります:

package FactoryPattern;

/**

  • @author ayqy
  • 不使用工厂模式,直���创建具体对象

*/ public class ClothesStore {

String type;//定义衣服类型
Clothes clothes;//衣服对象

/**
 * @author ayqy
 * 定义内部类 Clothes
 *
 */
class Clothes{
	String type;//类型
	String desc;//描述
	String cloth;//布料
	
	public Clothes(String type, String desc, String cloth){
		this.type = type;
		this.desc = desc;
		this.cloth = cloth;
	}
	
	public String toString(){
		return type+ "," + desc + "," + cloth;
	}
}

public ClothesStore(String type){
	this.type = type;
}

/**
 * @return 返回未经装饰加工的衣服
 */
private Clothes createClothes(String type){
	if(type.equals("外套")){
		return new Clothes("外套", "一件好看的外套", "麻布");
	}else if(type.equals("内衣")){
		return new Clothes("内衣", "一件舒适的内衣", "棉布");
	}else
		return null;
}

/**
 * @return 返回做好的衣服
 */
public Clothes getClothes(){
	clothes = createClothes(type);
	decorate(clothes);//对衣服进行装饰
	
	return clothes;
}

private void decorate(Clothes clothes){
	//给衣服添加装饰(图案、纹样等等)
	System.out.println("精心装饰完毕,衣服变得更漂亮了");
}

}

P.S. コードでは Clothes を内部クラスとして定義していますが、これは単に篇幅を節約して構造を簡素化するためであり、効果は同じです。

ClothesStore が Clothes に非常に強い依存関係を持っている(「具体」に過度に依存するのは良くないことです。。)ことがわかります。Clothes が変更された場合(例えば、新しいメンバー変数やメンバー関数が追加された場合)、ClothesStore はそれに応じて変更が必要になる可能性があります。特に、服のオブジェクトを new する部分:

/**
* @return 返回未经装饰加工的衣服
*/
private Clothes createClothes(String type){
if(type.equals("外套")){
		return new Clothes("外套", "一件好看的外套", "麻布");
	}else if(type.equals("内衣")){
		return new Clothes("内衣", "一件舒适的内衣", "棉布");
	}else
		return null;
}

新しい type が増えると、それに対応するために else if を追加する必要があります。また、ClothesStore が具体的な Clothes クラスとバインドされているため、ClothesStore は拡張が難しく、再利用が困難になります。

三.「シンプルファクトリパターン」

createClothes メソッドを ClothesFactory に移動して、静的ファクトリメソッドとして定義します:

package FactoryPattern.SimpleFactoryPattern;

/**

  • @author ayqy
  • 定义静态工厂方法

/ public class ClothesFactory { /* * @return 返回未经装饰加工的衣服 */ public static Clothes createClothes(String type){ if(type.equals("外套")){ return new Clothes("外套", "一件好看的外套", "麻布"); }else if(type.equals("内衣")){ return new Clothes("内衣", "一件舒适的内衣", "棉布"); }else return null; } }

P.S. 今回は Clothes を独立したクラスとして取り出す必要があります(内部クラスではアクセスできないため)。それに加えて、ClothesStore 内の getClothes メソッドもそれに応じて変更する必要があります。。これらの詳細は気にしないでください。

シンプルファクトリパターンを適用した後、new オブジェクトの部分を独立させることができました。このメリットは:

Clothes が変更された場合、ClothesStore の長いコードから Create 部分を探すのではなく、ClothesFactory で直接 create メソッドを修正できます。また、以前の「一般的な方法」と比較して、コードにほとんど変更がないため、以前のコードをシンプルファクトリパターンを適用したコードに簡単に変更できます。そのため、多くの開発者がこの方法を好みます。

「シンプルファクトリパターン」は本当のファクトリパターンではなく、その利点も非常に限られていますが、問題ありません。ファクトリメソッドパターンがあります。これは本物のファクトリパターンです。

四.ファクトリメソッドパターン

抽象的な「ファクトリメソッド」を定義して、具体的な実装を担当します。全新的な ClothesStore は以下のようになります:

package FactoryPattern.FactoryMethodPattern;

/**

  • @author ayqy
  • 使用工厂方法模式,定义抽象的工厂方法来 new 产品

*/ public abstract class ClothesStore {

String type;//定义衣服类型
Clothes clothes;//衣服对象

public ClothesStore(String type){
	this.type = type;
}

//定义工厂方法,由扩展类来实现具体制作细节
public abstract Clothes createClothes(String type);

/**
 * @return 返回做好的衣服
 */
public Clothes getClothes(){
	clothes = createClothes(type);
	decorate(clothes);//对衣服进行装饰
	
	return clothes;
}

private void decorate(Clothes clothes){
	//给衣服添加装饰(图案、纹样等等)
	System.out.println("精心装饰完毕,衣服变得更漂亮了");
}

}

ClothesStore が Abstract になったことがわかります。服の製作工程と実装詳細がカプセル化されていますが、Create プロセスは実装されていません。

次に、ClothesStore クラスを拡張して、具体的な Create 詳細を実装します:

package FactoryPattern.FactoryMethodPattern;

/**

  • @author ayqy
  • 扩展 ClothesStore,实现具体制作细节

*/ public class DefaultClothesStore extends ClothesStore{

public DefaultClothesStore(String type) {
	super(type);
}

/* 
 * 实现具体制作细节
 */
 @Override
public Clothes createClothes(String type) {
	if(type.equals("外套")){
		return new Clothes("外套", "一件好看的外套", "麻布");
	}else if(type.equals("内衣")){
		return new Clothes("内衣", "一件舒适的内衣", "棉布");
	}else
		return null;
}

}

はい、これでファクトリメソッドパターンを正常に適用できました。以前のシンプルファクトリパターンと比較して、この本物のファクトリパターンにはどのような特徴があるかを見てみましょう。

  1. 同様に new オブジェクトのプロセスとオブジェクトの振る舞いの分離を実現しましたが、異なるのは継承(拡張)を使用して実現したことです。つまり、冒頭で述べた「下放」(具体的な実装をより低いクラスレベルに配置する)です。
  2. 各具体的な Store は独自の Create 詳細を実装する必要がありますが、同時にベースクラスの Store の製作工程(decorate メソッドなど)を利用できます。
  3. 抽象的なファクトリメソッド 1 つでファクトリパターンを簡単に実現しました(Factory は全く現れませんでしたが、確かに「ファクトリ」を実現しました、不是吗?)。

五.抽象ファクトリパターン

抽象ファクトリパターンは前一种の方法の拡張です。上記では 1 つの製品しか Create できませんでしたが、多くの場合、一組の製品を Create する必要があります。例えば、服の原料には、布、染料、糸、ボタンなどがあります。この場合、抽象ファクトリパターンを適用して実装します:

package FactoryPattern.AbstractFactoryPattern;

/**

  • @author ayqy
  • 定义原料工厂

*/ public abstract class ResourcesFactory { public abstract Cloth getCloth();//获取布料 public abstract Color getColor();//获取染料 public abstract Button getButton();//获取纽扣 //需要的其它工厂方法 }

抽象ファクトリ内の型はすべてカスタムインターフェースです。例えば:

package FactoryPattern.AbstractFactoryPattern;

/**

  • @author ayqy
  • 定义 Cloth 接口 */ public interface Cloth { //属性 //行为 }

原料ファクトリがあるので、ClothesStore もこの新しい構造に適応するためにそれに応じて変更する必要があります:

package FactoryPattern.AbstractFactoryPattern;

/**

  • @author ayqy
  • 扩展 ClothesStore,实现具体制作细节

*/ public class DefaultClothesStore extends ClothesStore{

public DefaultClothesStore(String type, ResourcesFactory res) {
	super(type, res);
}

/* 
 * 实现具体制作细节
 */
 @Override
public Clothes createClothes(String type) {
	if(type.equals("外套")){
		//获取所需原料
		Cloth cloth = res.getCloth();
		Color color = res.getColor();
		Button button = res.getButton();
		//制作衣服
		return new Clothes("外套", color.toString() + button.toString(), cloth.toString());
	}else if(type.equals("内衣")){
		//获取所需原料
		Cloth cloth = res.getCloth();
		Color color = res.getColor();
		Button button = res.getButton();
		//制作衣服
		return new Clothes("内衣", color.toString() + button.toString(), cloth.toString());
	}else
		return null;
}

}

Store オブジェクトを作成する際に具体的な ResourcesFactory パラメータが必要です(具体的な原料ファクトリがすべての getXXX ファクトリメソッドを実装しています)。具体的な Store は具体的な製作プロセスを担当し、必要な原料は ResourceFactory から取得できます。具体的な Store が服を作った後、Store ベースクラスが工程加工(decorate メソッドなど)を担当し、最後に具体的な Store が精加工済みの服を返します。全体の構造は疎で、低結合、拡張が容易です。

それに加えて、OO 設計原則——「依存性逆転の原則」に言及する必要があります。クラス構造を観察することでわかります:

上位コンポーネント Store は Clothes に依存し、同時に下位コンポーネント ResourcesFactory も Clothes に依存しています(これが「依存性逆転」です。つまり、下位コンポーネントが逆に上位コンポーネントに依存し、同時に上位と下位のコンポーネントが両方とも抽象に依存する)。このような設計は拡張が容易という利点があります(抽象とは拡張可能ということです。。)

六.まとめ

実際、最初の部分はすでにまとめです。ここで強調したいのは、物事には両面性があり、良いものには必ず欠点が存在するということです。デザインパターンも例外ではありません。

抽象ファクトリパターンは確かに素晴らしいですが、致命的な欠点も存在します:多重抽象による構造の複雑化問題

コメント

コメントはまだありません

コメントを書く