DAY 14:Simple Factory Pattern,把复杂细节隐藏的小工厂

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

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

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

什麽是 Simple Factory Pattern?

由一个工厂将制作产品的细节隐藏,让使用者不需要不需要知道细节也能获得产品

在制作一个物件的时候,物件常常还需要有其他後制的处理,这些处理使用者不需要知道,使用者只需要获得此产品即可,所以需要将後制处理作封装

问题情境

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

实作有问题的 code 如下:

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

package factory

import "fmt"

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 main() {
	ps5 := PS5WithCD{}
	ps5.AddCDMachine()
	ps5.AddCPU()
	ps5.AddGPU()

	// or
	// ps5 := PS5WithDigital{}
	// ps5.AddCPU()
	// ps5.AddGPU()

	ps5.PlayGame()
}

使用者有可能会购买光碟版PS5WithCD{}或数位版PS5WithDigital{},并且回家玩游戏.PlayGame(),但 PS5 得组装方式.AddCDMachine().AddCPU().AddGPU()都是使用者不需要知道的。

想像一下你去买 PS5 的时候老板直接在你面前装 CPU 那画面也是够呛哈哈。

解决方式

我们需要CreatePS5()function 来将 PS5 的制作过程隐藏起来,如下:

package factory

import "fmt"

type PS5 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 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
}

func main() {
	ps5 := CreatePS5("PS5WithCD")
	ps5.PlayGame()
}

这样使用者就只需要CreatePS5()後即可直接.PlayGame()CreatePS5()有个特别的地方,

即透过 interface 来定义与外部沟通的方式

由於PS5WithCD{}PS5WithDigital{}始终是不同的东西,我们须将这两个物件「相同」的行为定义出来,来跟使用者说「这个产品可以玩 PS5 的游戏」,我们称这个动作为「抽象」。

所以 PS5 interface 将.PlayGame()这个行为抽象出来,只要能玩 PS5 游戏的产品,都称为 PS5 系列相关的产品,即 PS5 的光碟版与数位版。

最後整体 UML 如下(CreatePS5 不是 struct,所以我在上方标注这是一个 function 的区块):

PS5WithCD{}PS5WithDigital{}CreatePS5()生产,他们依赖PS5interface,而 user(main function)透过 interface 来操作生产出来的 PS5。


<<:  [Day 22] Leetcode 437. Path Sum III (C++)

>>:  提供 REST API / 限定栏位 / 格式化LocalDate - day12

【後转前要多久】# Day27 Angular - 介绍

终於进入到Angular环节了, 个人学习过程中主要以保哥的Angular教学为主。 Angular...

完全理解React的completeWork以及错误边界

点击进入React源码调试仓库。 概述 每个fiber节点在更新时都会经历两个阶段:beginWor...

day12: 模组化好的写法-为什麽要模组化

在过去 Javascript还没发展 common.js 或是 ESM,在使用 Javascript...

Day-11 其名为超级、於新电视再起的二代霸主超级任天堂

任天堂在红白机之後的这台後继机种超级任天堂、以下简称 SFC、是我家当年的第三台主机、也是我曾经拥有...

[Golang]同步工具-sync包的原子操作(下)-心智图总结

1. 比较和交换(compare and swap,简称CAS)跟交换(swap)有什麽不同? 比较...