
Factory 工厂模式
什么是工厂模式
工厂模式(Factory Pattern)是一种创建型设计模式,通过工厂模式我们将对象的创建过程封装起来,使得客户端代码可以请求一个对象,而不需要知道该对象的具体实现细节。
简单来讲,工厂模式是对对象创建过程的封装,从而使我们在使用的过程中无需感知对象的具体实现
应用场景
- 由于在 Go 语言中没有针对类的构造方法进行统一规范,因此在每次创建类实例的时候,都在业务方法中执行实例初始化细节将存在一下问题:
- 业务方法与组件类高度耦合,造成代码冗长、可读性差等问题
- 如果组件类定义发生变更,类的构造流程都需要进行改动,代码改动幅度大、可维护性差
因此我们可以遵循工厂模式的设计思路,实现类和业务方法的解耦、形成公共切面
优势
- 实现类和业务代码之间的解耦,如果类的构造过程发生变更,可以统一在工厂类进行处理,从而对业务方法屏蔽实例化细节
- 如果同时存在多个类聚拢在工厂类进行构造,则各个类的构造流程就形成了公共切面,可以进行公共逻辑的管理与复用
分类
简单工厂模式
首先我们先来看一个例子
package main
import "fmt"
type Animal struct { Assortment string}
func (a *Animal) Show() { switch a.Assortment { case "dog": fmt.Println("I am a dog") case "cat": fmt.Println("I am a cat") case "fish": fmt.Println("I am a fish") default: fmt.Println("I am a other animal") }}
func NewAnimal(name string) *Animal { var animal *Animal switch name { case "dog": animal = &Animal{Assortment: "dog"} case "cat": animal = &Animal{Assortment: "cat"} case "fish": animal = &Animal{Assortment: "fish"} default: animal = &Animal{Assortment: "other"} } return animal}
func main() { dog := NewAnimal("dog") dog.Show()
cat := NewAnimal("cat") cat.Show()
fish := NewAnimal("fish") fish.Show()}在上述代码中,针对于 Animal 这个 large 类,存在一下问题:
- 在 Animal 类中包含非常多的条件,整个类的代码相当冗长,代码越长,阅读难度、维护难度和测试难度也越大;而且大量条件语句的存在还将影响系统的性能,程序在执行过程中需要做大量的条件判断
- Animal 类的职责过重,它负责初始化和显示所有的动物对象,将各种动物对象的初始化代码和显示代码集中在一个类中实现,违反了*“单一职责原则”*,不利于类的重用和维护
- 当需要增加新类型的动物时,必须修改 Animal 类的构造函数
NewAnimal()和其他相关方法的代码,违反了*“开闭原则”* - 在业务层中,直接依赖 Animal 类型的构造方法
NewAnimal(),这样随着 Animal 的越来越复杂,那么业务层的开发逻辑也需要依赖 Animal 模块的更新,且随之改变,这样将导致业务层开发需要观察 Animal 模块做改动,影响业务层的开发效率和稳定性
现在我们来梳理一下其中的依赖关系
graph TD 业务逻辑层 --> 基础类模块
那我们如何进行解耦呢?其实很简单,只需要加一层中间层
graph TD 业务逻辑层 --> 工厂模块 --> 基础类模块
角色与职责分工
工厂(Factory)角色:简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。
抽象产品(AbstractProduct)角色:简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色:简单工厂模式所创建的具体实例对象。
classDiagram
class Factory {
+ CreateProduct() AbstractProduct
}
class ConcreteProduct {
+ AnOperation()
}
class AbstractProduct {
+ AnOperation()
}
Factory ..> ConcreteProduct : 创建
ConcreteProduct --|> AbstractProduct
实现思路
classDiagram
class Factory {
+ CreateProduct() AbstractProduct
}
class Dog {
+ Show()
}
class Cat {
+ Show()
}
class Fish {
+ Show()
}
class Animal {
+ Show
}
Factory ..> Dog : 创建
Factory ..> Cat : 创建
Factory ..> Fish : 创建
Animal <|-- Dog
Animal <|-- Cat
Animal <|-- Fish
- 对于拟构造组件类需要根据其共性,抽离出公共接口
- 在每个具体的组件类对接口加以实现
- 定义一个具体的工厂类,在构造方法中接受具体组件类,完成对该组件类的构造
package animal
import "fmt"
type Animal interface { Show()}
type Dog struct {}
func (d *Dog) Show() { fmt.Printf("I am a dog")}
type Cat struct {}
func (c *Cat) Show() { fmt.Printf("I am a cat")}
type Fish struct {}
func (f *Fish) Show() { fmt.Printf("I am a fish")}
package factory
type AnimalFactory struct{}
func NewAnimalFactory() *AnimalFactory { return &AnimalFactory{}}
func (f *AnimalFactory) CreateAnimal(type string) (Animal, error) { switch type { case "dog": return &Dog{}, nil case "cat": return &Cat{}, nil case "fish": return &Fish{}, nil default: return nil, fmt.Errorf("Animal type: %s is not supported yet", type) }}
package main
func main() { factory := NewAnimalFactory()
dog, err := factory.CreateAnimal("dog") if err != err { panic(err) } dog.Show()
cat, err := factory.CreateAnimal("cat") if err != err { panic(err) } cat.Show()
fish, err := factory.CreateAnimal("fish") if err != err { panic(err) } fish.Show()
house, err := factory.CreateAnimal("house") if err != err { panic(err) } house.Show()}优势
- 简单直观
- 实现了对象创建于使用的分离
- 构造各类组件时聚拢效果好,公共切面全面
劣势
- 工厂类职责过于集中
- 系统中类的个数增加,增加系统复杂度与理解难度
- 组件类扩展时,需要直接修改工厂的组件构造方法,违反开闭原则
适用场景
-
工厂类负责创建的对象较少
-
对与对象创建过程低依赖
工厂方法模式
在简单工厂模式中,我们违反了开闭原则,在这里我们对其设计流程进行一定修改,得到工厂方法模式
角色与职责分工
抽象工厂(Abstract Factory)角色:工厂方法模式的核心,任何工厂类都必须实现这个接口。
工厂(Concrete Factory)角色:具体工厂类是抽象工厂的一个实现,负责实例化产品对象。
抽象产品(Abstract Product)角色:工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。
具体产品(Concrete Product)角色:工厂方法模式所创建的具体实例对象。
classDiagram
class AbstractFactory {
+ CreateProduct(): AbstractProduct
}
class ConcreteProduct {
+ AnOperation()
}
class AbstractProduct {
+ AnOperation()
}
class Factory {
+ CreateProduct(): AbstractProduct
}
Factory ..> ConcreteProduct : 创建
Factory ..|> AbstractFactory
ConcreteProduct ..|> AbstractProduct
实现思路
classDiagram
class Animal {
+ Show()
}
class Dog {
+ Show()
}
class Cat {
+ Show()
}
class Fish {
+ Show()
}
class DogFactory {
+ CreateAnimal():Animal
}
class CatFactory {
+ CreateAnimal():Animal
}
class FishFactory {
+ CreateAnimal():Animal
}
class AnimalFactory {
+ CreateAnimal():Animal
}
DogFactory ..> Dog : 创建
CatFactory ..> Cat : 创建
FishFactory ..> Fish : 创建
DogFactory ..|> AnimalFactory
CatFactory ..|> AnimalFactory
FishFactory ..|> AnimalFactory
Dog ..|> Animal
Cat ..|> Animal
Fish ..|> Animal
- 关于组件的定义模式不变。由一个抽象的 Animal interface,多个具体的实现 Dog、Cat、Fish
- 将工厂类 AnimalFactory 由具体的实现类改为抽象的 interface
- 针对每类,提供出一个具体的工厂实现类,如 DogFactory、CatFactory、FishFactory
package abstract
type Animal interface { Show()}
type AnimalFactory interface { CreateAnimal() Animal}
package animal
import "fmt"
type Dog struct {}
func (d *Dog) Show() { fmt.Printf("I am a dog")}
type Cat struct {}
func (c *Cat) Show() { fmt.Printf("I am a cat")}
type Fish struct {}
func (f *Fish) Show() { fmt.Printf("I am a fish")}
package factory
type DogFactory struct { AnimalFactory}
func NewDogFactory AnimalFactory { return DogFactory{}}
func (f *DogFactory) CreateAnimal() Animal { return &Dog{}}
type CatFactory struct { AnimalFactory}
func NewCatFactory AnimalFactory { return DogFactory{}}
func (f *CatFactory) CreateAnimal() Animal { return &Cat{}}
type FishFactory struct { AnimalFactory}
func NewFishFactory AnimalFactory { return DogFactory{}}
func (f *FishFactory) CreateAnimal() Animal { return &Fish{}}
package main
func main() { dogFactory := NewDogFactory() dog := dogFactory.CreateAnimal() dog.Show()
catFactory := NewCatFactory() cat := catFactory.CreateAnimal() cat.Show()
fishFactory := NewFishFactory() fish := fishFactory.CreateAnimal() fish.Show()}优点
- 实现了对象创建与使用的分离
- 满足开闭原则,组件类扩展时无需更改接口与原组件类,代码入侵小,不会影响系统稳定性
缺点
- 增加系统中类的个数,系统复杂度与理解难度增加
- 代码冗余度高
- 公共切面少,公共逻辑反复声明,代码复用率低