2023/03/15

用Delphi體驗簡單工廠模式


簡單工廠模式是一種常用的創建型設計模式,它提供了一個統一的工廠方法,根據傳入的參數來創建不同的產品物件。

具體來說,簡單工廠模式通常包含以下角色:

  • 產品(Product):需要創建的具體產品。
  • 工廠(Factory):負責創建產品的工廠,包含一個靜態的工廠方法,根據客戶端傳入的參數創建對應的產品。
  • 客戶端(Client):使用工廠創建產品的客戶端。
  • 簡單工廠模式的核心是工廠方法,它負責根據客戶端傳入的參數創建對應的產品。客戶端不需要知道具體的產品是如何創建的,只需要知道傳入什麼參數就可以得到對應的產品。

在設計軟體時,我們常常需要創建不同的物件,而這些物件通常有共同的介面或繼承關係。當我們需要創建這些物件時,可以使用簡單工廠模式。

簡單工廠模式是一種創建型模式,它提供了一個共同的介面,用於創建不同類型的物件,而不需要直接指定它們的類型。簡單工廠模式可以隱藏物件創建的細節,並提高程式碼的可讀性和可維護性。

在 Delphi 中,我們可以使用 TComponent 或介面 (Interface) 來實現簡單工廠模式。下面我們將以製作蛋餅為例來展示如何使用 TComponent 和介面實現簡單工廠模式。

使用 TComponent 實現簡單工廠模式

首先,我們需要定義一個基礎的蛋餅類別 TChineseOmelette,並繼承自 TComponent。TChineseOmelette 包含兩個虛擬方法 GetName 和 GetPrice,用於取得蛋餅的名稱和價格。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
unit ChineseOmelette;

interface

uses
System.Classes;

type
  TChineseOmelette = class(TComponent)
public
  function GetName: string; virtual; abstract;
  function GetPrice: Double; virtual; abstract;
end;

implementation

end.

接下來,我們需要定義具體的蛋餅類別,包括雞肉蛋餅、牛肉蛋餅、豬肉蛋餅和起司蛋餅。這些具體的蛋餅類別都繼承自 TChineseOmelette,並實現其 GetName 和 GetPrice 方法。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
unit ChineseOmelettes;

interface

uses
System.Classes;

type
  TChineseOmelette = class(TComponent)
  public
    function GetName: string; virtual; abstract;
    function GetPrice: Double; virtual; abstract;
  end;

  TChickenOmelette = class(TChineseOmelette)
  public
    function GetName: string; override;
    function GetPrice: Double; override;
  end;

  TBeefOmelette = class(TChineseOmelette)
  public
    function GetName: string; override;
    function GetPrice: Double; override;
  end;

  TPorkOmelette = class(TChineseOmelette)
  public
    function GetName: string; override;
    function GetPrice: Double; override;
  end;

  TCheeseOmelette = class(TChineseOmelette)
  public
    function GetName: string; override;
    function GetPrice: Double; override;
  end;

implementation

function TChickenOmelette.GetName: string;
begin
  Result := '雞肉蛋餅';
end;

function TChickenOmelette.GetPrice: Double;
begin
  Result := 30.0;
end;

function TBeefOmelette.GetName: string;
begin
  Result := '牛肉蛋餅';
end;

function TBeefOmelette.GetPrice: Double;
begin
  Result := 35.0;
end;

function TPorkOmelette.GetName: string;
begin
  Result := '豬肉蛋餅';
end;

function TPorkOmelette.GetPrice: Double;
begin
  Result := 25.0;
end;

function TCheeseOmelette.GetName: string;
begin
  Result := '起司蛋餅';
end;

function TCheeseOmelette.GetPrice: Double;
begin
  Result := 40.0;
end;

end.

現在我們已經定義了基礎類別 TChineseOmelette 和具體類別 TChickenChineseOmelette、TBeefChineseOmelette、TPorkChineseOmelette 和 TCheeseChineseOmelette。下一步我們需要定義一個工廠類別 TChineseOmeletteFactory,用於創建不同類型的蛋餅物件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
unit ChineseOmeletteFactory;

interface

uses
  ChineseOmelette;

type
  TChineseOmeletteType = (cotChicken, cotBeef, cotPork, cotCheese);

  TChineseOmeletteFactory = class
  public
    class function CreateOmelette(OmeletteType: TChineseOmeletteType): TChineseOmelette;
  end;

implementation

uses
  ChineseOmeletteTypes;

class function TChineseOmeletteFactory.CreateOmelette(OmeletteType: TChineseOmeletteType): TChineseOmelette;
begin
  case OmeletteType of
    cotChicken:
      Result := TChickenOmelette.Create(nil);
    cotBeef:
      Result := TBeefOmelette.Create(nil);
    cotPork:
      Result := TPorkOmelette.Create(nil);
    cotCheese:
      Result := TCheeseOmelette.Create(nil);
  else
    Result := nil;
  end;
end;

end.

現在我們已經定義了 TChineseOmeletteFactory,我們可以使用它來創建不同類型的蛋餅物件。

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
procedure TForm1.Button1Click(Sender: TObject);
var
  ChineseOmelette: TChineseOmelette;
begin
  // 創建雞肉蛋餅
  ChineseOmelette := TChineseOmeletteFactory.CreateChineseOmelette(btChicken) as TChineseOmelette;
  Memo1.Lines.Add(Format('%s: %.2f', [ChineseOmelette.GetName, ChineseOmelette.GetPrice]));
  ChineseOmelette.Free;

  // 創建牛肉蛋餅
  ChineseOmelette := TChineseOmeletteFactory.CreateChineseOmelette(btBeef) as TChineseOmelette;
  Memo1.Lines.Add(Format('%s: %.2f', [ChineseOmelette.GetName, ChineseOmelette.GetPrice]));
  ChineseOmelette.Free;

  // 創建豬肉蛋餅
  ChineseOmelette := TChineseOmeletteFactory.CreateChineseOmelette(btPork) as TChineseOmelette;
  Memo1.Lines.Add(Format('%s: %.2f', [ChineseOmelette.GetName, ChineseOmelette.GetPrice]));
  ChineseOmelette.Free;

  // 創建起司蛋餅
  ChineseOmelette := TChineseOmeletteFactory.CreateChineseOmelette(btCheese) as TChineseOmelette;
  Memo1.Lines.Add(Format('%s: %.2f', [ChineseOmelette.GetName, ChineseOmelette.GetPrice]));
  ChineseOmelette.Free;
end;

至此,我們已經完成了 Delphi 簡單工廠模式的設計與實現。現在我們可以輕鬆地創建不同類型的蛋餅物件,而不必關心其具體實現細節。

使用 Interface (介面)實現簡單工廠模式

簡單工廠模式是一個常見的設計模式,在軟體開發中使用廣泛。通過這種設計模式,我們可以確實隱藏物件的具體實現細節,提高程式碼的可維護性和擴充。

除了以上的 TComponent 實現方式,我們還可以使用介面來實現簡單工廠模式。以下是介面實現方式的範例:

  1
  2
  3
  4
  5
  6
  7
  8
  9
 10
 11
 12
 13
 14
 15
 16
 17
 18
 19
 20
 21
 22
 23
 24
 25
 26
 27
 28
 29
 30
 31
 32
 33
 34
 35
 36
 37
 38
 39
 40
 41
 42
 43
 44
 45
 46
 47
 48
 49
 50
 51
 52
 53
 54
 55
 56
 57
 58
 59
 60
 61
 62
 63
 64
 65
 66
 67
 68
 69
 70
 71
 72
 73
 74
 75
 76
 77
 78
 79
 80
 81
 82
 83
 84
 85
 86
 87
 88
 89
 90
 91
 92
 93
 94
 95
 96
 97
 98
 99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
unit ChineseOmelette;

interface

type
  IChineseOmelette = interface
    function GetName: string;
    function GetPrice: Double;
  end;

  TChineseOmeletteType = (cotChicken, cotBeef, cotPork, cotCheese);

  TChineseOmeletteFactory = class
  public
    class function CreateChineseOmelette(ChineseOmeletteType: TChineseOmeletteType): IChineseOmelette;
  end;

implementation

uses
  ChineseOmeletteVarieties;

type
  TChickenChineseOmelette = class(TInterfacedObject, IChineseOmelette)
  public
    function GetName: string;
    function GetPrice: Double;
  end;

  TBeefChineseOmelette = class(TInterfacedObject, IChineseOmelette)
  public
    function GetName: string;
    function GetPrice: Double;
  end;

  TPorkChineseOmelette = class(TInterfacedObject, IChineseOmelette)
  public
    function GetName: string;
    function GetPrice: Double;
  end;

  TCheeseChineseOmelette = class(TInterfacedObject, IChineseOmelette)
  public
    function GetName: string;
    function GetPrice: Double;
  end;

{ TChickenChineseOmelette }

function TChickenChineseOmelette.GetName: string;
begin
  Result := '雞肉蛋餅';
end;

function TChickenChineseOmelette.GetPrice: Double;
begin
  Result := 30.0;
end;

{ TBeefChineseOmelette }

function TBeefChineseOmelette.GetName: string;
begin
  Result := '牛肉蛋餅';
end;

function TBeefChineseOmelette.GetPrice: Double;
begin
  Result := 35.0;
end;

{ TPorkChineseOmelette }

function TPorkChineseOmelette.GetName: string;
begin
  Result := '豬肉蛋餅';
end;

function TPorkChineseOmelette.GetPrice: Double;
begin
  Result := 25.0;
end;

{ TCheeseChineseOmelette }

function TCheeseChineseOmelette.GetName: string;
begin
  Result := '起司蛋餅';
end;

function TCheeseChineseOmelette.GetPrice: Double;
begin
  Result := 40.0;
end;

{ TChineseOmeletteFactory }

class function TChineseOmeletteFactory.CreateChineseOmelette(ChineseOmeletteType: TChineseOmeletteType): IChineseOmelette;
begin
  case ChineseOmeletteType of
    cotChicken:
      Result := TChickenChineseOmelette.Create;
    cotBeef:
      Result := TBeefChineseOmelette.Create;
    cotPork:
      Result := TPorkChineseOmelette.Create;
    cotCheese:
      Result := TCheeseChineseOmelette.Create;
  else
    raise Exception.Create('Invalid Chinese omelette type.');
  end;
end;

end.

使用介面實現簡單工廠模式的核心在於定義一個公用介面,所有的具體產品都實現這個介面。工廠類別則根據不同的產品類型創建對應的具體產品,並返回公用介面類型的實例。

在使用簡單工廠模式時,我們需要注意以下幾點:

  1. 工廠類別需要負責創建產品實例,並返回公用介面類型的實例。
  2. 具體產品需要實現公用介面,以便工廠類別能夠創建對應的產品實例。
  3. 工廠類別需要知道所有支援的產品類型,並根據類型創建對應的產品實例。
  4. 簡單工廠模式在增加新的產品時,需要修改工廠類別的代碼。因此,它的擴充性較低,但對於簡單的應用場景來說,它仍是一個簡單而有效的設計模式。

總結

簡單工廠模式是一個常用的設計模式,它可以將物件的創建與使用分離開來,提高程式碼的可維護性和擴充性。在 Delphi 中,我們可以使用 TComponent 或介面來實現簡單工廠模式。透過這個模式,我們可以輕鬆地創建不同類型的物件,而不必關心其具體實現細節。

和你分享。😉







沒有留言:

張貼留言