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

文章目录

  • 设计模式大白话——工厂模式
      • 1.1、简单工厂:
      • 1.2、工厂方法
      • 1.3、抽象工厂

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

1.1、简单工厂:

  • 场景与思路

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

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

  • 示例代码:

    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张图片

1.2、工厂方法

  • 场景与思路

    ​ 现在,我们披萨店铺的规模不断地变大,准备在其他几个地区开分店,不同地区的口味都不一样,这个时候你会发现,上面的方法就不太适用了。
    ​ 简单梳理一下,这次相对于之前的变化是:多了很多店铺,我们可以对店铺进行抽象,这个时候不同的店铺子类只需要去实现各自的简单工厂即可!

  • 示例代码

    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生产者)都进行了抽象,这样以来不同的店铺生产的披萨的方法都可以是不一样的,灵活性好,也好拓展。为了方便理解,我这里放上一个图片:

    设计模式大白话——工厂模式_第2张图片

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

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

1.3、抽象工厂

  • 场景与思路

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

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

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

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

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

  • 示例代码

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

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

    设计模式大白话——工厂模式_第3张图片

  • 模式定义

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

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

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

你可能感兴趣的:(设计模式,设计模式,golang,后端,简单工厂模式,工厂方法模式,抽象工厂模式)