重走Java設計模式——抽象工廠模式(Abstract Factory Pattern)
抽象工廠模式
抽象工廠模式是所有形態的工廠模式中最為抽象和最具一般性的一種形態。 抽象工廠模式是指當有多個抽象角色時,使用的一種工廠模式。抽象工廠模式可以向客戶端提供一個介面,使客戶端在不必指定產品的具體的情況下,建立多個產品族中的產品物件。根據里氏替換原則,任何接受父型別的地方,都應當能夠接受子型別。因此,實際上系統所需要的,僅僅是型別與這些抽象產品角色相同的一些例項,而不是這些抽象產品的例項。換言之,也就是這些抽象產品的具體子類的例項。工廠類負責建立抽象產品的具體子類的例項。
抽象工廠的定義
為建立一組相關或相互依賴的物件提供一個介面,而且無需指定他們的具體類。
抽象工廠例項程式碼
建立Shape
Color
介面和實現這些介面的實體類。下一步是建立抽象工廠類 AbstractFactory
。接著定義工廠類ShapeFactory
和ColorFactory
,這兩個工廠類都是擴充套件了 AbstractFactory
。然後建立一個工廠創造器/生成器類FactoryProducer
。
AbstractFactoryPatternDemo
,我們的演示類使用FactoryProducer
來獲取AbstractFactory
物件。它將向 AbstractFactory
傳遞形狀資訊 Shape(CIRCLE / RECTANGLE / SQUARE),以便獲取它所需物件的型別。同時它還向 AbstractFactory 傳遞顏色資訊 Color(RED / GREEN / BLUE),以便獲取它所需物件的型別。
1.為形狀建立一個介面。
public interface Shape {
void draw();
}
2.建立實現介面的實體類
Rectangle.java
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Inside Rectangle::draw() method.");
}
}
Square.java
public class Square implements Shape { @Override public void draw() { System.out.println("Inside Square::draw() method."); } }
Circle.java
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Inside Circle::draw() method.");
}
}
3.為顏色建立一個介面
Color.java
public interface Color {
void fill();
}
4.建立實現介面的實體類
Red.java
public class Red implements Color {
@Override
public void fill() {
System.out.println("Inside Red::fill() method.");
}
}
Green.java
public class Green implements Color {
@Override
public void fill() {
System.out.println("Inside Green::fill() method.");
}
}
Blue.java
public class Blue implements Color {
@Override
public void fill() {
System.out.println("Inside Blue::fill() method.");
}
}
5.為 Color 和 Shape 物件建立抽象類來獲取工廠
AbstractFactory.java
public abstract class AbstractFactory {
public abstract Color getColor(String color);
public abstract Shape getShape(String shape) ;
}
6.建立擴充套件了 AbstractFactory 的工廠類,基於給定的資訊生成實體類的物件
ShapeFactory.java
public class ShapeFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
if(shapeType == null){
return null;
}
if(shapeType.equalsIgnoreCase("CIRCLE")){
return new Circle();
} else if(shapeType.equalsIgnoreCase("RECTANGLE")){
return new Rectangle();
} else if(shapeType.equalsIgnoreCase("SQUARE")){
return new Square();
}
return null;
}
@Override
public Color getColor(String color) {
return null;
}
}
ColorFactory.java
public class ColorFactory extends AbstractFactory {
@Override
public Shape getShape(String shapeType){
return null;
}
@Override
Color getColor(String color) {
if(color == null){
return null;
}
if(color.equalsIgnoreCase("RED")){
return new Red();
} else if(color.equalsIgnoreCase("GREEN")){
return new Green();
} else if(color.equalsIgnoreCase("BLUE")){
return new Blue();
}
return null;
}
}
7.建立一個工廠創造器/生成器類,通過傳遞形狀或顏色資訊來獲取工廠
FactoryProducer.java
public class FactoryProducer {
public static AbstractFactory getFactory(String choice){
if(choice.equalsIgnoreCase("SHAPE")){
return new ShapeFactory();
} else if(choice.equalsIgnoreCase("COLOR")){
return new ColorFactory();
}
return null;
}
}
8.使用 FactoryProducer 來獲取 AbstractFactory,通過傳遞型別資訊來獲取實體類的物件
AbstractFactoryPatternDemo.java
public class AbstractFactoryPatternDemo {
public static void main(String[] args) {
// 獲取形狀工廠
AbstractFactory shapeFactory = FactoryProducer.getFactory("SHAPE");
// 獲取形狀為 Circle 的物件
Shape shape1 = shapeFactory.getShape("CIRCLE");
// 呼叫 Circle 的 draw 方法
shape1.draw();
// 獲取形狀為 Rectangle 的物件
Shape shape2 = shapeFactory.getShape("RECTANGLE");
// 呼叫 Rectangle 的 draw 方法
shape2.draw();
// 獲取形狀為 Square 的物件
Shape shape3 = shapeFactory.getShape("SQUARE");
// 呼叫 Square 的 draw 方法
shape3.draw();
// 獲取顏色工廠
AbstractFactory colorFactory = FactoryProducer.getFactory("COLOR");
// 獲取顏色為 Red 的物件
Color color1 = colorFactory.getColor("RED");
// 呼叫 Red 的 fill 方法
color1.fill();
// 獲取顏色為 Green 的物件
Color color2 = colorFactory.getColor("Green");
// 呼叫 Green 的 fill 方法
color2.fill();
// 獲取顏色為 Blue 的物件
Color color3 = colorFactory.getColor("BLUE");
// 呼叫 Blue 的 fill 方法
color3.fill();
}
}
9.執行上面程式碼,輸出結果
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.
Inside Red::fill() method.
Inside Green::fill() method.
Inside Blue::fill() method.
抽象工廠模式的優缺點
優點
當一個產品族中的多個物件被設計成一起工作時,它能保證客戶端始終只使用同一個產品族中的物件。
缺點
產品族擴充套件非常困難,要增加一個系列的某一產品,既要在抽象的 Creator 里加程式碼,又要在具體的裡面加程式碼。
抽象工廠模式使用場景
1、QQ 的一鍵換面板,一下子就是換一整套面板。 2、生成不同作業系統的程式。
使用的注意事項
產品族難擴充套件,產品等級易擴充套件。
產品族
上面抽象工廠模式中有提到產品族,什麼是產品族呢?產品族
是指位於不同產品等級結構中,功能相關聯的產品組成的家族。一般是位於不同的等級結構中的相同位置上。顯然,每一個產品族中含有產品的數目,與產品等級結構的數目是相等的,形成一個二維的座標系,水平座標是產品等級結構,縱座標是產品族。叫做相圖。
當有多個不同的等級結構的產品時,如果使用工廠方法模式就勢必要使用多個獨立的工廠等級結構來對付這些產品的等級結構。如果這些產品等級結構是平行的,會導致多個平行的工廠等級結構。
抽象工廠模式使用同一個 工廠等級結構負責這些不同產品等級結構產品物件的建立。
對於每一個產品族,都有一個具體工廠。而每一個具體工廠建立屬於同一個產品族,但是分屬於不同等級結構的產品。
通過引進抽象工廠模式,可以處理具有相同(或者相似)等級結構的多個產品族中的產品物件的建立問題。
由於每個具體工廠角色都需要負責兩個不同等級結構的產品物件的建立,因此每個工廠角色都需要提供兩個工廠方法,分別用於建立兩個等級結構的產品。既然每個具體工廠角色都需要實現這兩個工廠方法,所以具有一般性,不妨抽象出來,移動到抽象工廠角色中加以宣告。