简单工厂模式不属于 GoF 23 个经典设计模式,但通常将它作为学习其它工厂模式的基础。
简单工厂模式(Simple Factory Pattern)
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式,属于类创建型模式。
简单工厂模式包含 3 个角色:
- Factory(工厂角色)
- 负责实现创建所有产品实例的内部逻辑。
- 提供了静态工厂方法 factoryMethod(),可以被外界直接调用,创建所需的产品对象。
- Product(抽象产品角色)
- 工厂类创建的所有对象的父类,封装了各种产品对象的公有方法。
- ConcreteProduct(具体产品角色)
- 简单工厂模式的创建目标,所有被创建的对象都充当这个角色的某个具体类的实例。
- 每个具体产品角色都继承了抽象产品角色,需要实现的抽象产品中声明的抽象方法。
在简单工厂模式中,客户端通过工厂类来创建一个产品类的实例,而无须直接使用 new 关键字来创建对象,它是工厂模式家族中最简单的一员。
应用案例
云管平台(CMP)中需要对多种类型的虚拟机进行管理,例如:OpenStack、VMware、Aliyun 等。
可以使用工厂模式来创建不同类型的虚拟机对象。
- 未使用设计的代码
缺点:
- 有 3 种类型的虚拟机,每种类型虚拟机的 create 和 delete 方法都不同,势必导致产生大量冗长的代码。
- 每种类型虚拟机操作的代码自身也会持续增长,增长的逻辑中不确定是每种类型虚拟机都有的,还是只有一种类型或者几种类型有这样的业务,会导致代码编写位置的混乱。
- 每增加一种类型的虚拟机,就需要新增一个 if,随着纳管类型的增加,代码将会持续大幅增长。
package main
import "fmt"
type VirtualMachine struct {
name string
vmType string
openstackField string
vmwareField string
aliyunField string
}
// 构造函数
func newVirtualMachine(name, vmType string) *VirtualMachine {
if vmType == "OpenStack" {
return &VirtualMachine{
name: name,
vmType: vmType,
openstackField: "OpenStack Field",
}
} else if vmType == "VMware" {
return &VirtualMachine{
name: name,
vmType: vmType,
openstackField: "VMware Field",
}
} else if vmType == "Aliyun" {
return &VirtualMachine{
name: name,
vmType: vmType,
openstackField: "Aliyun Field",
}
}
return nil
}
func (v VirtualMachine) create() {
if v.vmType == "OpenStack" {
fmt.Println("调用 OpenStack 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
} else if v.vmType == "VMware" {
fmt.Println("调用 VMware 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
} else if v.vmType == "Aliyun" {
fmt.Println("调用 Aliyun 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
}
func (v VirtualMachine) delete() {
if v.vmType == "OpenStack" {
fmt.Println("调用 OpenStack 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
} else if v.vmType == "VMware" {
fmt.Println("调用 VMware 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
} else if v.vmType == "Aliyun" {
fmt.Println("调用 Aliyun 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
}
func main() {
vm := newVirtualMachine("OpenStack", "OpenStack")
vm.create()
}
- 使用设计模式的代码
优点:
- 每种类型的虚拟机都有自己独立的属性,将这些独立属性放在各类虚拟机子类中,通用属性使用父类。
- 每种类型的虚拟机的操作都在各自方法中单独实现,避免耦合在一起相互影响。
package main
type VirtualMachineInterface interface {
create()
delete()
}
type VirtualMachine struct {
name string
vmType string
}
代码语言:javascript复制package main
import "fmt"
type OpenStackVirtualMachine struct {
VirtualMachine
openStackField string
}
func (vm OpenStackVirtualMachine) create() {
fmt.Println("调用 OpenStack 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
func (vm OpenStackVirtualMachine) delete() {
fmt.Println("调用 OpenStack 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
代码语言:javascript复制package main
import "fmt"
type VMwareVirtualMachine struct {
vm VirtualMachine
vmwareField string
}
func (vm VMwareVirtualMachine) create() {
fmt.Println("调用 VMware 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
func (vm VMwareVirtualMachine) delete() {
fmt.Println("调用 VMware 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
代码语言:javascript复制package main
import "fmt"
type AliyunVirtualMachine struct {
vm VirtualMachine
aliyunField string
}
func (vm AliyunVirtualMachine) create() {
fmt.Println("调用 Aliyun 接口 create 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
func (vm AliyunVirtualMachine) delete() {
fmt.Println("调用 Aliyun 接口 delete 虚拟机 API")
fmt.Println("... 大量业务逻辑代码 ...")
}
代码语言:javascript复制package main
type VirtualMachineFactory struct {
vmType string
}
func (factory VirtualMachineFactory) create() VirtualMachineInterface {
if factory.vmType == "OpenStack" {
return new(OpenStackVirtualMachine)
} else if factory.vmType == "VMware" {
return new(VMwareVirtualMachine)
} else if factory.vmType == "Aliyun" {
return new(AliyunVirtualMachine)
}
return nil
}
func main() {
factory := new(VirtualMachineFactory)
factory.vmType = "OpenStack"
vm := factory.create()
vm.create()
factory.vmType = "VMware"
vm = factory.create()
vm.create()
factory.vmType = "Aliyun"
vm = factory.create()
vm.create()
}
总结
有些对象属于一类产品,但是属性不同,业务也不同。这种对象可以使用工厂模式来创建。
使用工厂模式的好处是,将对象的创建逻辑从代码主流程中分拆出去,这样主流程代码可读性更高,同时也可以减少逻辑因为同类对象代码耦合在一起引起的逻辑混乱。