设计模式大白话——工厂模式

文章目录

设计模式大白话------工厂模式

1.1、简单工厂:

  • 场景与思路

    ​ 现在需要开一个 Pizza 店,Pizza 店可以生产各种口味的 Pizza

    ​ 既然要生产各种各样的 Pizza,那就会很容易想到要对 Pizza 进行抽象,这个时候我们只需要创建一个 PizzaStore 专门去用于生产即可。

  • 示例代码:

    go 复制代码
    package main
    
    // Pizza 产品的抽象
    type Pizza interface {
    	GetName() string
    }
    
    type NYPizza struct {
    	Name string
    }
    
    func (p NYPizza) GetName() string {
    	return p.Name
    }
    
    type ChicagoPizza struct {
    	Name string
    }
    
    func (p ChicagoPizza) GetName() string {
    	return p.Name
    }
    
    type PizzaStore struct {
    }
    
    func (ps PizzaStore) OrderPizza(t string) Pizza {
    	// 生产不同口味的披萨
    	if t == "Cheese" {
    		// 芝士味
    		return NYPizza{Name: "Cheese Pizza"}
    	} else if t == "Chocolate" {
    		// 巧克力味
    		return ChicagoPizza{Name: "Chocolate Pizza"}
    	}
    
    	return nil
    }
    
    func main() {
    	pizzaStore := PizzaStore{}
    
    	println(pizzaStore.OrderPizza("Cheese").GetName())    // Cheese Pizza
    	println(pizzaStore.OrderPizza("Chocolate").GetName()) // Chocolate Pizza
    }
  • 分析

    简单工厂更像是一个编程习惯,对要生产的各种各样的产品进行了抽象

1.2、工厂方法

  • 场景与思路

    ​ 现在,我们披萨店铺的规模不断地变大,准备在其他几个地区开分店,不同地区的口味都不一样,这个时候你会发现,上面的方法就不太适用了。

    ​ 简单梳理一下,这次相对于之前的变化是:多了很多店铺,我们可以对店铺进行抽象,这个时候不同的店铺子类只需要去实现各自的简单工厂即可!

  • 示例代码

    go 复制代码
    package main
    
    // Pizza 产品的抽象
    type Pizza interface {
    	GetName() string
    }
    
    type NYPizza struct {
    	name string
    }
    
    func (p NYPizza) GetName() string {
    	return p.name
    }
    
    type ChicagoPizza struct {
    	name string
    }
    
    func (p ChicagoPizza) GetName() string {
    	return p.name
    }
    
    // PizzaStore 创建者的抽象
    type PizzaStore interface {
    	OrderPizza(t string) Pizza
    }
    
    type NYPizzaStore struct {
    }
    
    func (s NYPizzaStore) OrderPizza(t string) Pizza {
    	if t == "1" {
    		return NYPizza{name: "NY 1"}
    	}
    	return NYPizza{name: "NY 2"}
    }
    
    type ChicagoPizzaStore struct {
    }
    
    func (s ChicagoPizzaStore) OrderPizza(t string) Pizza {
    	if t == "1" {
    		return ChicagoPizza{name: "Chicago 1"}
    	}
    	return ChicagoPizza{name: "Chicago 2"}
    }
    
    func main() {
    	NYPizzaStore := NYPizzaStore{}
    	println(NYPizzaStore.OrderPizza("1").GetName()) // NY 1
    
    	ChicagoPizzaStore := ChicagoPizzaStore{}
    	println(ChicagoPizzaStore.OrderPizza("1").GetName()) // Chicago 1
    }
  • 分析

    ​ 工厂方法模式里,对 Pizza产品 )和 PizzaStore生产者)都进行了抽象,这样以来不同的店铺生产的披萨的方法都可以是不一样的,灵活性好,也好拓展。为了方便理解,我这里放上一个图片:

  • 模式定义
    工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把示例化推迟到子类。

    值得注意的是:这里所谓的的"决定",并不是指子类运行时做决定,而是指在编写创建者类时,不需要制定实际创建的产品时哪一个。因为你选择了什么样的创建者,自然也就决定了创建什么样的产品。

1.3、抽象工厂

  • 场景与思路

    ​ 现在又有新的变化了!每个分店位于不同的城市,因此制作披萨的原料也是不一样的,因此生产出来的同类型的披萨也是有差别的,例如:面团和芝士。

    ​ 因为每个城市的原料各不相同,因此我们抽象了一个原料工厂接口,此接口用于获取面团和奶酪。此外,面团和奶酪也需要进行抽象。如下所示:

    go 复制代码
    // PizzaIngredientFactory 披萨原料工厂的抽象
    type PizzaIngredientFactory interface {
    	CreateDough() Dough
    	CreateCheese() Cheese
    	// 其他原料...
    }
    
    // Dough 面团接口
    type Dough interface {
    	GetName() string
    }
    
    // Cheese 芝士接口
    type Cheese interface {
    	GetName() string
    }

    ​ 具备如上接口之后,不同地区的披萨的只需要实现各自的方法即可。现在制作披萨的方式也与之前有所不同,披萨的制作现在依赖于原料工厂,如下所示:

    go 复制代码
    // Pizza 生产的披萨
    type Pizza struct {
    	factory PizzaIngredientFactory
    }
    
    func (p Pizza) Prepare() {
    	fmt.Printf("正在使用 %s 酱料和 %s 芝士准备披萨\n", p.factory.CreateDough().GetName(), p.factory.CreateCheese().GetName())
    	// 此处省略了具体的制作过程
    }

  • 示例代码

    go 复制代码
    package main
    
    import "fmt"
    
    // Pizza 生产的披萨
    type Pizza struct {
    	factory PizzaIngredientFactory
    }
    
    func (p Pizza) Prepare() {
    	fmt.Printf("正在使用 %s 酱料和 %s 芝士准备披萨\n", p.factory.CreateDough().GetName(), p.factory.CreateCheese().GetName())
    	// 此处省略了具体的制作过程
    }
    
    // PizzaIngredientFactory 披萨原料工厂的抽象
    type PizzaIngredientFactory interface {
    	CreateDough() Dough
    	CreateCheese() Cheese
    	// 其他原料...
    }
    
    // Dough 面团接口
    type Dough interface {
    	GetName() string
    }
    
    // NYDough 纽约面团
    type NYDough struct {
    }
    
    func (d NYDough) GetName() string {
    	return "NY Dough"
    }
    
    // ChicagoDough 芝加哥面团
    type ChicagoDough struct {
    }
    
    func (d ChicagoDough) GetName() string {
    	return "Chicago Dough"
    }
    
    // Cheese 芝士接口
    type Cheese interface {
    	GetName() string
    }
    
    // NYCheese 纽约芝士
    type NYCheese struct {
    }
    
    func (c NYCheese) GetName() string {
    	return "NY Cheese"
    }
    
    // ChicagoCheese 芝加哥芝士
    type ChicagoCheese struct {
    }
    
    func (c ChicagoCheese) GetName() string {
    	return "Chicago Cheese"
    }
    
    // NYPizzaIngredientFactory 纽约披萨原料工厂
    type NYPizzaIngredientFactory struct {
    }
    
    func (f NYPizzaIngredientFactory) CreateDough() Dough {
    	return NYDough{}
    }
    
    func (f NYPizzaIngredientFactory) CreateCheese() Cheese {
    	return NYCheese{}
    }
    
    // ChicagoPizzaIngredientFactory 芝加哥披萨原料工厂
    type ChicagoPizzaIngredientFactory struct {
    }
    
    func (f ChicagoPizzaIngredientFactory) CreateDough() Dough {
    	return ChicagoDough{}
    }
    
    func (f ChicagoPizzaIngredientFactory) CreateCheese() Cheese {
    	return ChicagoCheese{}
    }
    
    func main() {
    	NYPizza := Pizza{factory: NYPizzaIngredientFactory{}}
    	NYPizza.Prepare() // 正在使用 NY Dough 酱料和 NY Cheese 芝士准备披萨
    
    	ChicagoPizza := Pizza{factory: ChicagoPizzaIngredientFactory{}}
    	ChicagoPizza.Prepare() // 正在使用 Chicago Dough 酱料和 Chicago Cheese 芝士准备披萨
    }
  • 分析

    为了方便理解,可以参考如下的图片去理解

  • 模式定义

    抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确制定与体类。(说人话就是接口中定义了一组方法用于创建各种对象,可以结合上图去理解)

    如果你细心观察的话,会发现,抽象工厂模式的每个方法其实使用的都是工厂方法

最后,感谢你看到了这里。如果此文章有说的不对的地方,也欢迎纠正。

相关推荐
Victor35614 分钟前
MongoDB(87)如何使用GridFS?
后端
Victor35617 分钟前
MongoDB(88)如何进行数据迁移?
后端
小红的布丁33 分钟前
单线程 Redis 的高性能之道
redis·后端
GetcharZp39 分钟前
Go 语言只能写后端?这款 2D 游戏引擎刷新你的认知!
后端
宁瑶琴2 小时前
COBOL语言的云计算
开发语言·后端·golang
普通网友2 小时前
阿里云国际版服务器,真的是学生党的性价比之选吗?
后端·python·阿里云·flask·云计算
IT_陈寒3 小时前
Vue的这个响应式问题,坑了我整整两小时
前端·人工智能·后端
Soofjan4 小时前
Go 内存回收-GC 源码1-触发与阶段
后端
shining4 小时前
[Golang]Eino探索之旅-初窥门径
后端
掘金者阿豪4 小时前
Mac 程序员效率神器:6 个我每天都在用的 Mac 工具推荐(Alfred / Paste / PixPin / HexHub / iTerm2 /)
后端