iT邦幫忙

2021 iThome 鐵人賽

DAY 5
1
Software Development

也該是時候學學 Design Pattern 了系列 第 5

Day 05: Creational patterns - Simple Factory Method

目的

傳入參數後,藉由 switch-case 來建立一系列擁有相同親代的物件

說明

作為入門 Design Pattern 的第一個模式,Simple Factory Method 本身不屬於「物件導向設計模式」所列的 23 個模式內,其價值在於了解「簡單」、「常用」的寫法也屬於設計模式的一種。

Simple Factory Method 的作法是:

  1. 先決定要建立的物件,該物件視為親代,可以用 Class、Abstract Class 或 Interface。
  2. 建立一系列的子代物件,子代負責實作細節。
  3. 建立工廠,藉由傳入的參數搭配 switch-case 後決定生產哪個物件。

UML 圖

Simple Factory Method UML Diagram

使用 Java 實作

產品親代:PETBottle

public abstract class PETBottle {
    protected String smell = "";
    protected String color = "";

    public void setBottle(String smell, String color) {
        this.smell = smell;
        this.color = color;
    }

    public abstract String getTaste();
}

產品子代:CokeWaterOrangeJuice

public class Coke extends PETBottle {
    @Override
    public String getTaste() {
        return "這瓶可樂的顏色:" + color + ",香味是:" + smell;
    }
}

public class Water extends PETBottle {
    @Override
    public String getTaste() {
        return "這瓶水的顏色:" + color + ",香味是:" + smell;
    }
}

public class OrangeJuice extends PETBottle {
    @Override
    public String getTaste() {
        return "這瓶柳橙汁的顏色:" + color + ",香味是:" + smell;
    }
}

工廠:PETBottleFactory

public class PETBottleFactory {
    public static PETBottle getPETBottle(String option) throws Exception {
        PETBottle bottle = null;

        switch (option) {
            case "coke":
                bottle = new Coke();
                break;
            case "Water":
                bottle = new Water();
                break;
            case "OrangeJuice":
                bottle = new OrangeJuice();
                break;
            default:
                throw new Exception("輸入錯誤");
        }

        return bottle;
    }
}

實作:

public class PETBottleSimpleFactorySample {
    public static void main(String[] args) throws Exception {
        String option = "coke";
        String smell = "甜甜的";
        String color = "黑黑的";
        PETBottle bottle = PETBottleFactory.getPETBottle(option);
        bottle.setBottle(smell, color);
        System.out.println(bottle.getTaste());
    }
}

使用 JavaScript 實作

受限於 JavaScript 沒有虛擬型別、無法限制型別。

產品親代:PETBottle

/** @abstract */
class PETBottle {
  constructor() {
    this.smell = '';
    this.color = '';
  }

  setBottle(smell, color) {
    this.smell = smell;
    this.color = color;
  }

  getTaste() { return; }
}

產品子代:CokeWaterOrangeJuice

class Coke extends PETBottle {
  /** @override */
  getTaste() {
    return "這瓶可樂的顏色:" + this.color + ",香味是:" + this.smell;
  }
}

class Water extends PETBottle {
  /** @override */
  getTaste() {
    return "這瓶水的顏色:" + this.color + ",香味是:" + this.smell;
  }
}

class OrangeJuice extends PETBottle {
  /** @override */
  getTaste() {
    return "這瓶柳橙汁的顏色:" + this.color + ",香味是:" + this.smell;
  }
}

工廠:PETBottleFactory

class PETBottleFactory {
  static getPETBottle(option) {
    /** @type PETBottle */
    let bottle = null;

    switch (option) {
      case "coke":
        bottle = new Coke();
        break;
      case "Water":
        bottle = new Water();
        break;
      case "OrangeJuice":
        bottle = new OrangeJuice();
        break;
      default:
        throw new Error("輸入錯誤");
    }

    return bottle;
  }
}

實作:

const PETBottleSimpleFactorySample = () => {
  const option = "coke";
  const smell = "甜甜的";
  const color = "黑黑的";
  const bottle = PETBottleFactory.getPETBottle(option);
  bottle.setBottle(smell, color);
  console.log(bottle.getTaste());
};

PETBottleSimpleFactorySample();

總結

Simple Factory Method 最適合當作第一個入門的模式,在於簡單好懂:

  • 當需要產生相同類型的「服務」時,可以先建立一個親代,再建立一堆子代,最後用一個生產者物件負責生產。
  • 使用時,將參數交給生產者物件即可決定要使用哪個子代。

缺點則是要增加子代項目時,必須修改「生產者物件」,也就是 switch 的區塊,這點會破壞 SOLIDOCP,每次修改程式碼時,不該動到既有的程式碼。

因為這一點,才有後續兩個與 Factory 有關的模式。


上一篇
Day 04: 進入主題前的補充:SOLID
下一篇
Day 06: Creational patterns - Factory Method
系列文
也該是時候學學 Design Pattern 了31

1 則留言

0
TD
iT邦新手 4 級 ‧ 2021-09-20 22:13:59

維特的兩條腿 那個 UML 圖好像看不到耶?

我要留言

立即登入留言