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

文章目录

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

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 芝士准备披萨
    }
  • 分析

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

  • 模式定义

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

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

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

相关推荐
Q_19284999067 分钟前
基于Spring Boot的个人健康管理系统
java·spring boot·后端
liutaiyi87 分钟前
Redis可视化工具 RDM mac安装使用
redis·后端·macos
Q_192849990614 分钟前
基于Springcloud的智能社区服务系统
后端·spring·spring cloud
xiaocaibao77717 分钟前
Java语言的网络编程
开发语言·后端·golang
会说法语的猪2 小时前
springboot实现图片上传、下载功能
java·spring boot·后端
凡人的AI工具箱2 小时前
每天40分玩转Django:实操多语言博客
人工智能·后端·python·django·sqlite
Cachel wood2 小时前
Django REST framework (DRF)中的api_view和APIView权限控制
javascript·vue.js·后端·python·ui·django·前端框架
m0_748234082 小时前
Spring Boot教程之三十一:入门 Web
前端·spring boot·后端
越甲八千2 小时前
重温设计模式--代理、中介者、适配器模式的异同
设计模式·适配器模式
想成为高手4992 小时前
国产之光--仓颉编程语言的实战案例分析
后端