DAY 15:Factory Method Pattern,把复杂的逻辑拆分至小工厂中

工厂模式主要有三种不同的实作:

  • Simple Factory Pattern
  • Factory Method Pattern
  • Abstract Factory Pattern

这三种实作由简单到复杂,今天会介绍 Simple Factory Pattern 延伸的 Factory Method Pattern

什麽是 Factory Method Pattern?

将复杂的生产逻辑再拆分至特定工厂,由使用者端决定要使用什麽工厂来生产产品

以昨天的例子简单得来说,就是「将 if else/swtich 的逻辑拆分至不同工厂」,即:

func CreatePS5(style string) PS5 {
	switch style {
	case "PS5WithCD":
		ps5 := &PS5WithCD{}
		ps5.AddCDMachine()
		ps5.AddCPU()
		ps5.AddGPU()
		return ps5
	case "PS5WithDigital":
		ps5 := &PS5WithDigital{}
		ps5.AddCPU()
		ps5.AddGPU()
		return &PS5WithDigital{}
	}
	return nil
}

拆分至PS5WithCDFactory{}PS5WithDigital{},「单一产品由单一工厂生产」,这样做有什麽优缺点呢?

优点:

  • 符合开闭原则,在新增产品时不必修改 function 实作(对修改封闭),但可以透过不同工厂来新增(对扩充开放)
  • 修改都是扩充的,不是改 function 实作,所以把原本的逻辑改坏的可能性不高
  • 如果创建逻辑过於复杂,Simple Factory Pattern 的逻辑会相当复杂,而 Factory Method Pattern 将逻辑拆成小工厂可以避免这个问题

缺点:

  • 为每新增一个产品都需要新增一个工厂,如果产品众多,程序码会有数不尽的工厂,让系统变得很复杂

问题情境

延续昨天的情境,要生产 PS5 主机光碟版数位版给使用者,但使用者不需要知道「如何生产 CPU、显示晶片与加装光碟机」,使用者只需要获得此产品就行。

解决方式

程序码如下:

(相关的 code 在Github - go-design-patterns)

package main

import "fmt"

type GameMachineFactory interface {
	Create() GameMachine
}

type PS5WithCDFactory struct{}

func (f *PS5WithCDFactory) Create() GameMachine {
	ps5 := &PS5WithCD{}
	ps5.AddCDMachine()
	ps5.AddCPU()
	ps5.AddGPU()
	return &PS5WithCD{}
}

type PS5WithDigitalFactory struct{}

func (f *PS5WithDigitalFactory) Create() GameMachine {
	ps5 := &PS5WithDigital{}
	ps5.AddCPU()
	ps5.AddGPU()
	return &PS5WithDigital{}
}

type GameMachine interface {
	PlayGame()
}

type PS5WithCD struct{}

func (p PS5WithCD) PlayGame() {
	fmt.Println("loading cd...play!")
}
func (p PS5WithCD) AddCDMachine() {
	fmt.Println("adding cd machine...done!")
}
func (p PS5WithCD) AddCPU() {
	fmt.Println("adding cpu...done!")
}
func (p PS5WithCD) AddGPU() {
	fmt.Println("adding gpu...done!")
}

type PS5WithDigital struct{}

func (p PS5WithDigital) PlayGame() {
	fmt.Println("loading digital file...play!")
}
func (p PS5WithDigital) AddCPU() {
	fmt.Println("adding cpu...done!")
}
func (p PS5WithDigital) AddGPU() {
	fmt.Println("adding gpu...done!")
}

func User(gameMachineFactory GameMachineFactory) {
	gameMachine := gameMachineFactory.Create()
	gameMachine.PlayGame()
}

func main() {
	User(&PS5WithCDFactory{})
}

UML 图如下:

可以与昨天 UML 图比较,关键差异在於「把工厂也建立了 inferface」,使用者就可以使用GameMachineFactory interface 来去选择哪间工厂,而选好了工厂後,工厂依照 interface 把Create()提供给使用者操作,创建出游戏机,之後就与 Simple Factory Pattern 是一样使用者依照GameMachineinterface 来游玩游戏。


<<:  【D14】熟悉厨具:订阅Subscribe

>>:  EP14 - [TDD] 订单 Order 类别

Day 21 - ESG已经是个不可不知的显学

图片来源 延续上一篇所谈的气候变迁与净零碳排, 在大势所趋之下, 近年无论是在投资与企业经营上的一...

Material UI in React [ Day 26 ] Styles API (part 1)

API 今天来厘清 @material-ui/core/styles 的 API。 createGe...

教练,我想自干作业系统!

前言 写一个 OS 是多麽美好的事,在有限的生命中千万不要遗漏了它。 -- 王佑中博士 笔者在开始撰...

求助 Excel VBA 搜寻关键字後贴到其他的tab的写法

各位先备好 如果有一个excel里面资料大概有50列,而每一行都是记载着不同的资讯,譬如:姓名/电话...

D21. 学习基础C、C++语言

D21. 题目练习uva350 #include <stdio.h> #include ...