文章目录
- 设计模式大白话——工厂模式
- 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.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
(生产者)都进行了抽象,这样以来不同的店铺生产的披萨的方法都可以是不一样的,灵活性好,也好拓展。为了方便理解,我这里放上一个图片: -
模式定义
工厂方法模式定义了一个创建对象的接口,但由子类决定要实例化的类是哪一个,工厂方法让类把示例化推迟到子类。值得注意的是:这里所谓的的“决定”,并不是指子类运行时做决定,而是指在编写创建者类时,不需要制定实际创建的产品时哪一个。因为你选择了什么样的创建者,自然也就决定了创建什么样的产品。
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 芝士准备披萨 }
-
分析
为了方便理解,可以参考如下的图片去理解
-
模式定义
抽象工厂模式提供一个接口,用于创建相关或依赖对象的家族,而不需要明确制定与体类。(说人话就是接口中定义了一组方法用于创建各种对象,可以结合上图去理解)
如果你细心观察的话,会发现,抽象工厂模式的每个方法其实使用的都是工厂方法
最后,感谢你看到了这里。如果此文章有说的不对的地方,也欢迎纠正。