Fork me on GitHub

Programming Design Notes

Design Pattern - Abstract Factory

| Comments

上一篇已經介紹過的 Factory Pattern 可以將建立實例的程式碼抽取出來, 並可以提供絡不同的物件使用。Abstract Factory Pattern 其實和 Factory Pattern 很相似,但 Abstract Factory 比較偏向建立同一系統的物件。

同一系列的意思是彼此的物件有一定的關連,例如: 輪子、引擎、車架、方向盤、儀標板等等。 這些都是組成車子的組件,這些組件亦由可以由不同廠商去開發,Abstract Factory 扮演角色就是廠商。 更改廠商,就可以建立不同樣式的車子。

看看以下例子應該有助你明白這個模式:


公司要開發一款迷宮遊戲,建立迷宮的組件有:『牆壁』、『門』和『道路』。 遊戲在不同的關卡會顯示不同風格的迷宮,首先要將做出組件的介面和建立一個工廠介面。

組件介面:

(Component.java) download
package component;

public interface Component {

    public void draw();

}
(Door.java) download
package component;

public interface Door extends Component {

}
(Wall.java) download
package component;

public interface Wall extends Component {

}
(Road.java) download
package component;

public interface Road extends Component {

}
(Labyrinth.java) download
package component;

import java.util.Random;

import factory.LabyrinthComponentFactory;

public class Labyrinth implements Component {

    private LabyrinthComponentFactory labyrinthFactory;

    public Labyrinth(LabyrinthComponentFactory labyrinthFactory) {
        this.labyrinthFactory = labyrinthFactory;
    }

    @Override
    public void draw() {
        Random random = new Random();
        for (int i = 0; i < 10; i++) {
            switch (random.nextInt(15)) {
            case 0:
                labyrinthFactory.createDoor().draw();
                break;
            case 1:
            case 2:
            case 3:
            case 4:
            case 5:
                labyrinthFactory.createRoad().draw();
                break;
            default:
                labyrinthFactory.createWall().draw();
                break;
            }
        }

    }

}

藍色風格的組件:

(BlueDoor.java) download
package component.blue;

import component.Door;

public class BlueDoor implements Door {

    @Override
    public void draw() {
        System.out.println("Blue Door");
    }

}
(BlueWall.java) download
package component.blue;

import component.Wall;

public class BlueWall implements Wall {

    @Override
    public void draw() {
        System.out.println("Blue Wall");
    }

}
(BlueRoad.java) download
package component.blue;

import component.Road;

public class BlueRoad implements Road {

    @Override
    public void draw() {
        System.out.println("Blue Road");
    }

}

綠色風格的組件:

(GreenDoor.java) download
package component.green;

import component.Door;

public class GreenDoor implements Door {

    @Override
    public void draw() {
        System.out.println("Green Door");
    }

}
(GreenWall.java) download
package component.green;

import component.Wall;

public class GreenWall implements Wall {

    @Override
    public void draw() {
        System.out.println("Green Wall");
    }

}
(GreenRoad.java) download
package component.green;

import component.Road;

public class GreenRoad implements Road {

    @Override
    public void draw() {
        System.out.println("Green Road");
    }

}

工廠介面:

(LabyrinthComponentFactory.java) download
package factory;

import component.Door;
import component.Road;
import component.Wall;

public interface LabyrinthComponentFactory {

    public Wall createWall();

    public Door createDoor();

    public Road createRoad();

}
(BlueStyleLabyrinthComponentFactory.java) download
package factory;

import component.Door;
import component.Road;
import component.Wall;
import component.blue.BlueDoor;
import component.blue.BlueRoad;
import component.blue.BlueWall;

public class BlueStyleLabyrinthComponentFactory implements
        LabyrinthComponentFactory {

    @Override
    public Wall createWall() {
        return new BlueWall();
    }

    @Override
    public Door createDoor() {
        return new BlueDoor();
    }

    @Override
    public Road createRoad() {
        return new BlueRoad();
    }

}
(GreenStyleLabyrinthComponentFactory.java) download
package factory;

import component.Door;
import component.Road;
import component.Wall;
import component.green.GreenDoor;
import component.green.GreenRoad;
import component.green.GreenWall;

public class GreenStyleLabyrinthComponentFactory implements
        LabyrinthComponentFactory {

    @Override
    public Wall createWall() {
        return new GreenWall();
    }

    @Override
    public Door createDoor() {
        return new GreenDoor();
    }

    @Override
    public Road createRoad() {
        return new GreenRoad();
    }

}
(Main.java) download
import component.Labyrinth;

import factory.BlueStyleLabyrinthComponentFactory;
import factory.GreenStyleLabyrinthComponentFactory;
import factory.LabyrinthComponentFactory;

public class Main {

    public static void main(String[] args) {

        LabyrinthComponentFactory blueStyleLabyrinthComponentFactory = new BlueStyleLabyrinthComponentFactory();
        LabyrinthComponentFactory greenStyleLabyrinthComponentFactory = new GreenStyleLabyrinthComponentFactory();

        Labyrinth blueStyleLabyrinth = new Labyrinth(blueStyleLabyrinthComponentFactory);
        Labyrinth greenStyleLabyrinth = new Labyrinth(greenStyleLabyrinthComponentFactory);

        blueStyleLabyrinth.draw();

        System.out.println("------------------");

        greenStyleLabyrinth.draw();

    }

}
執行結果
Blue Road
Blue Road
Blue Road
Blue Wall
Blue Road
Blue Door
Blue Wall
Blue Road
Blue Road
Blue Road
------------------
Green Wall
Green Wall
Green Wall
Green Road
Green Wall
Green Wall
Green Wall
Green Road
Green Wall
Green Road

在建立 Labyrinth 時,只需將工廠交給 Labyrinth 就可以建立不同風格的迷宮。

要新增更多風格的組件,只需要建立相對應的工廠就可以了,完全不需要改動 Labyrinth.draw 的程式碼。

不過 Abstract Factory 有一個缺點,如果你要新増一個原先不存在的組件,例如加一個『陷阱』, 你便需要更改 LabyrinthFactory 這個介面。


以下的圖片是描述 Abstract Factory Pattern 的 Class Diagram。(From Wiki)