文章

抽象工廠模式 - Abstract Factory Pattern

用途

透過抽象工廠模式使客戶端程式碼與具體產品的實現解耦,提高程式碼的可擴展性和可維護性

classDiagram
  Client ..> IFactory
  Client ..> ProductA
  Client ..> ProductB
  ProductA <|-- FactoryAProductA
  ProductA <|-- FactoryBProductA
  FactoryAProductA <.. ConcreteFactoryA
  FactoryAProductB <.. ConcreteFactoryA
  FactoryBProductA <.. ConcreteFactoryB
  ProductB <|-- FactoryAProductB
  ProductB <|-- FactoryBProductB
  FactoryBProductB <.. ConcreteFactoryB
  IFactory <|-- ConcreteFactoryA
  IFactory <|-- ConcreteFactoryB
  note for Client "Inject Factory to Generate Product"
  class ProductA{
    <<Abstract>>
    +DoSomething()*
  }
  class ProductB{
    <<Abstract>>
    +DoSomething()*
  }
  class FactoryAProductA{
    +DoSomething()
  }
  class FactoryAProductB{
    +DoSomething()
  }
  class FactoryBProductA{
    +DoSomething()
  }
  class FactoryBProductB{
    +DoSomething()
  }
  class IFactory{
    <<Interface>>
    +CreateProductA() ProductA
    +CreateProductB() ProductB
  }
  class ConcreteFactoryA{
    +CreateProductA() ProductA
    +CreateProductB() ProductB
  }
  class ConcreteFactoryB{
    +CreateProductA() ProductA
    +CreateProductB() ProductB
  }
  class Client{
    -IFactory factory
    +Client(ConcreteFactory factory)
    +Operation()
  }

例子

GUI

假設我們正在開發一個應用程式,該應用程式需要支援不同的操作系統,如 WindowsmacOS
而在每個操作系統下,我們需要提供一套相應的 GUI 控制元件,如按鈕、文本框和標籤等

在這個例子中,我們可以定義一個抽象工廠介面 IGUIFactory,該介面定義了創建不同操作系統下的 GUI 控制元件的方法,如 CreateButton、CreateTextBox 和 CreateLabel

然後,我們實現具體的工廠類別,如 WindowsGUIFactory 和 MacOSGUIFactory,它們分別實現了 IGUIFactory 接口
在這些具體工廠類別中,我們可以根據操作系統的不同,創建相應的 GUI 控制元件

接下來,我們定義抽象的 GUI 控制元件類別,如 Button、TextBox 和 Label,它們定義了這些控制元件的共同屬性和行為

最後,我們有具體的 GUI 控制元件類別,如 WindowsButton、WindowsTextBox、MacOSButton 和 MacOSTextBox,它們分別實現了抽象控制元件類別,並提供了特定操作系統下的控制元件實現

這樣,當我們需要創建 GUI 控制元件時,我們可以使用對應操作系統的具體工廠類別,它們將根據所選的操作系統創建出相應的控制元件
這樣我們就可以通過抽象工廠模式實現操作系統和控制元件的解耦,同時保持程式碼的可擴展性和可維護性

Product

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
// 抽象 GUI 控制元件類別
public abstract class Button
{
    public abstract void Render();
}

public abstract class TextBox
{
    public abstract void Render();
}

public abstract class Label
{
    public abstract void Render();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 具體 MacOS 控制元件類別
public class MacOSButton : Button
{
    public override void Render()
    {
        Console.WriteLine("Render MacOSButton");
    }
}

public class MacOSTextBox : TextBox
{
    public override void Render()
    {
        Console.WriteLine("Render MacOSTextBox");
    }
}

public class MacOSLabel : Label
{
    public override void Render()
    {
        Console.WriteLine("Render MacOSLabel");
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
// 具體 Windows 控制元件類別
public class WindowsButton : Button
{
    public override void Render()
    {
        Console.WriteLine("Render WindowsButton");
    }
}

public class WindowsTextBox : TextBox
{
    public override void Render()
    {
        Console.WriteLine("Render WindowsTextBox");
    }
}

public class WindowsLabel : Label
{
    public override void Render()
    {
        Console.WriteLine("Render WindowsLabel");
    }
}

Factory

1
2
3
4
5
6
7
// 抽象工廠介面
public interface IGUIFactory
{
    Button CreateButton();
    TextBox CreateTextBox();
    Label CreateLabel();
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 具體的 MacOS 工廠
public class MacOSGUIFactory : IGUIFactory
{
    public Button CreateButton()
    {
        return new MacOSButton();
    }

    public TextBox CreateTextBox()
    {
        return new MacOSTextBox();
    }

    public Label CreateLabel()
    {
        return new MacOSLabel();
    }
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
// 具體的 Windows 工廠
public class WindowsGUIFactory : IGUIFactory
{
    public Button CreateButton()
    {
        return new WindowsButton();
    }

    public TextBox CreateTextBox()
    {
        return new WindowsTextBox();
    }

    public Label CreateLabel()
    {
        return new WindowsLabel();
    }
}

Client

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
// 用戶端程式碼
public class Client
{
    private IGUIFactory _guiFactory;

    public Client(IGUIFactory guiFactory)
    {
        _guiFactory = guiFactory;
    }

    public void RenderUI()
    {
        Button button = _guiFactory.CreateButton();
        TextBox textBox = _guiFactory.CreateTextBox();
        Label label = _guiFactory.CreateLabel();

        button.Render();
        textBox.Render();
        label.Render();
    }
}

Program

1
2
3
4
5
6
7
8
9
10
11
// 使用 Windows 工廠
IGUIFactory windowsFactory = new WindowsGUIFactory();
Client windowsClient = new Client(windowsFactory);
windowsClient.RenderUI();

Console.WriteLine();

// 使用 MacOS 工廠
IGUIFactory macosFactory = new MacOSGUIFactory();
Client macosClient = new Client(macosFactory);
macosClient.RenderUI();

延伸

本文章以 CC BY 4.0 授權