简单工厂
什么是简单工厂
定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。
基本流程
- 定义产品接口:
- 创建一个抽象的产品类或接口,定义产品的共同特征。
- 实现具体产品类:
- 实现一个或多个具体产品类,它们继承自产品接口或抽象类,具体化产品接口的抽象方法。
- 定义工厂接口:
- 设计一个工厂类,它包含一个或多个方法,用于创建不同类型的产品对象。
- 实现工厂方法:
- 在工厂类中实现创建产品对象的逻辑。通常,这个方法会根据输入参数来决定创建哪种具体产品对象。
- 客户端调用:
- 客户端代码通过调用工厂类的工厂方法,并传入必要的参数,以获取所需的产品对象。
- 返回产品对象:
- 工厂方法根据传入的参数创建相应的具体产品对象,并将其返回给客户端。
- 使用产品对象:
- 客户端使用返回的产品对象执行所需的操作,而无需关心对象的具体创建细节。
结构
**工厂:**创建对象,创建产品实例的内部逻辑,外部不感知。外部直接调用,创建所需的产品对象
**产品:**所有对象的公共方法,也就是父类。内部方法只声明不定义。
具体产品: 具体产品的公共方法的具体实现。
使用场景
- 对象种类有限:当需要创建的对象种类较少时,使用简单工厂模式可以保持工厂方法的业务逻辑简洁,避免复杂化。
- 客户端解耦:客户端仅需要了解如何传递正确的参数给工厂类,而无需关心对象的具体创建过程。这降低了客户端与对象创建逻辑之间的耦合度。
- 简化客户端代码:在对象创建逻辑较为直接时,客户端不需要了解对象的具体类型或创建细节,只需与工厂类交互即可获得所需的对象。
- 创建逻辑透明化:客户端不需要了解对象是如何被创建和组装的,只需关注如何使用工厂类提供的接口来获取对象。
- 对象创建灵活性:当系统需要灵活地创建一系列相关或相互依赖的对象时,简单工厂模式提供了一种集中管理和扩展的简便方式
优点
- 封装性:隐藏了对象创建的复杂性,客户端不需要知道具体的创建细节。
- 客户端解耦:客户端与具体产品类解耦,只需与工厂类交互。
- 可维护性:当需要添加新的产品时,只需扩展工厂类,不需要修改客户端代码。
- 简单性:在对象创建逻辑相对简单且对象种类有限的情况下,实现容易理解。
缺点
- 扩展性限制:如果产品类的数量非常多,工厂方法中的业务逻辑将变得复杂。
- 紧耦合:工厂类与产品类之间存在紧密耦合,一旦产品类变化,工厂类也需要相应修改。
- 增加系统的复杂度:随着产品种类的增加,工厂类的方法数量和复杂度也会增加。
- 难以形成框架:由于工厂类集中了所有产品类的创建逻辑,这可能使得形成更高层次的框架变得困难。
使用注意事项
- 明确职责:确保工厂类职责清晰,避免将非创建逻辑的业务代码放入工厂类中。
- 避免过度集中:如果工厂类变得过于复杂,考虑使用其他创建型模式,如工厂方法模式或抽象工厂模式。
- 扩展性考虑:设计时考虑未来可能的扩展,确保工厂类能够容易地添加新产品。
- 单一职责原则:工厂类应该只负责对象的创建,遵循单一职责原则。
- 使用接口引用:客户端应该通过抽象产品类的接口引用产品,而不是具体产品类的实例。
- 避免暴露实现:不要在工厂类中暴露具体的产品类实现,以保持系统的灵活性和可维护性。
代码实例
package designpattern
import "fmt"
// 定义产品接口,创建一个接口定义产品的公共行为
type Product interface {
Use()
}
// 定义具体产品类,实现产品接口
type ConcreteProductA struct{}
func (p *ConcreteProductA) Use() {
fmt.Println("Product A is used")
}
// 定义具体产品类,实现产品接口
type ConcreteProductB struct{}
func (p *ConcreteProductB) Use() {
fmt.Println("Product B is used")
}
// 定义简单工厂类,负责创建具体产品类的实例
type SimpleFactory struct{}
// 实习工厂方法,根据传入的产品类型,创建具体产品类的实例并返回
func (f *SimpleFactory) CreateProduct(productType string) Product {
switch productType {
case "A":
return &ConcreteProductA{}
case "B":
return &ConcreteProductB{}
default:
return nil
}
}
// 客户端调用
func main() {
factory := SimpleFactory{}
productA := factory.CreateProduct("A")
productA.Use()
productB := factory.CreateProduct("B")
productB.Use()
}
工厂方法模式
什么是工厂模式
在简单工厂模式下只提供一个工厂类,该工厂处于对产品类进行实例化的中心位置,它需要知道每个产品对象的创建细节,并决定何时实例化哪个产品类,当有新产品加入时,必须修改工厂类
工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪个类实例化。不再提供一个统一的工厂类来创建所有的产品对象,针对不同的产品提供不同的工厂。提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象。适用于需要将对象创建过程封装起来,同时提供系统扩展性的场景。
基本流程
- 定义产品接口:
创建一个产品接口,定义了所有具体产品对象的公共接口。 - 创建具体产品类:
实现产品接口,为每一个具体产品提供实现。 - 定义工厂接口:
创建一个工厂接口,用于定义创建产品的方法。 - 实现具体工厂类:
为每一个具体工厂类提供工厂接口的实现,每个具体工厂类只能创建一个具体产品。 - 客户端使用:
客户端通过工厂接口与具体工厂类交互,获取所需的产品对象,而无需知道具体的产品类。
结构
- 工厂:不在实现创建所有的具体产品实例,只声明一个创建接口,具体初始化动作交给具体工厂
- 具体工厂:实现工厂的方法,返回一个具体产品的实例
- 产品:所有对象的公共方法,也就是父类。内部方法只声明不定义。
- 具体产品:由具体工厂创建,实现父类方法
使用场景
- 当系统需要在运行时根据不同条件创建不同类的实例时。
- 当一个类不知道它必须创建的实例的具体类时。
- 当需要让系统的扩展更加容易,不修改现有代码的情况下引入新的类时。
- 在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库、创建文件等。
- 遵循开闭原则:当需要添加新产品时,只需添加相应的具体工厂类和产品类,而无需修改现有的工厂类和产品类代码,这符合软件设计的开闭原则(对扩展开放,对修改封闭)。
优点
- 封装性:
工厂方法模式隐藏了对象创建的具体细节,使得客户端不需要知道具体的类是如何实现的。 - 扩展性:
当需要引入新的类时,只需添加相应的具体类和相应的具体工厂类,无需修改已有代码。 - 解耦:
工厂方法模式将对象的创建和使用分离,降低了模块间的耦合度。 - 代码复用:
可以在类的层次结构中引入新的类,而不影响其他对象的使用。
缺点
- 增加系统复杂度:
每增加一个产品类别,都需要增加一个具体类和对象的具体工厂类,这可能会导致系统中类的数量急剧增加。 - 增加系统的抽象性:
在添加新的产品类时,需要对工厂方法的接口进行扩展,这增加了系统的抽象性和理解难度。 - 增加系统的重量:
工厂方法模式增加了额外的工厂类,这可能会使系统变得庞大。
使用注意事项
- 定义清晰的接口:
确保产品接口和工厂接口清晰明确,易于理解和使用。 - 避免过度扩展:
考虑系统的扩展性,但也要避免过度设计,引入不必要的复杂性。 - 保持一致性:
所有具体工厂类应该遵循相同的接口,以保持一致性。
代码实例
package designpattern
//定义产品接口,声明具体产品对象的公共接口
type Product interface {
Operation()
}
// 创建具体产品类, 实现产品接口
type ConcreteProductA struct {}
func (p *ConcreteProductA) Operation() {
fmt.Println("ConcreteProductA operation")
}
type ConcreteProductB struct {}
func (p *ConcreteProductB) Operation() {
fmt.Println("ConcreteProductB operation")
}
// 定义工厂接口,声明创建产品对象的公共接口
type Factory interface {
CreateProduct() Product
}
// 具体工厂类,实现工厂接口
type ConcreteFactoryA struct {}
func (f *ConcreteFactoryA) CreateProduct() Product {
return &ConcreteProductA{}
}
type ConcreteFactoryB struct {}
func (f *ConcreteFactoryB) CreateProduct() Product {
return &ConcreteProductB{}
}
func main() {
factoryA:=&ConcreteFactoryA{}
productA:=factoryA.CreateProduct()
productA.Operation()
factoryB:=&ConcreteFactoryB{}
productB:=factoryB.CreateProduct()
productB.Operation()
}
抽象工厂
当系统中存在多种产品,且每个工厂类仅负责单一产品的创建时,可能会导致工厂类的数量急剧增加,从而增加了系统的复杂度和维护成本。为了解决这一问题,可以引入抽象工厂模式,它允许一个工厂类负责生产一系列相关的产品,这些产品通常被称为一个“产品族”。
使用抽象工厂模式,可以将具有相关性的多个产品的创建逻辑集中管理,从而减少系统中工厂类的数量。这种方法不仅简化了工厂类的结构,而且提高了代码的可维护性和可扩展性。当需要引入新的产品族时,只需添加一个新的抽象工厂实现,而无需修改现有的工厂类,这样就有效地控制了系统的扩展。
什么是抽象工厂
产品等级结构:产品等级结构即产品的继承结构
产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品
抽象工厂模式提供了一种创建对象族的解决方案,它扩展了工厂方法模式的理念。在抽象工厂模式中,每个具体工厂类不仅负责生成单一产品,而是能够生产一系列相关联的产品,形成一个完整的产品族。这种模式强调了产品间的内在联系,并允许系统更加灵活地处理产品族的创建。
**抽象工厂模式(Abstract Factory Pattern):**提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,它是一种对象创建型模式。
基本流程
- 定义抽象产品:
为每个产品族定义一个抽象产品类或接口。 - 实现具体产品:
为每个抽象产品提供一个或多个具体实现。 - 定义抽象工厂:
创建一个抽象工厂接口,声明一组方法,用于创建各种抽象产品。 - 实现具体工厂:
为每个产品族提供一个具体工厂类,实现抽象工厂接口,并创建具体的产品。 - 客户端使用:
客户端通过抽象工厂接口与具体工厂类交互,请求创建产品族中的一个或多个产品。 - 获取产品:
具体工厂根据请求创建并返回具体产品实例。 - 产品使用:
客户端使用返回的产品实例,完成所需的功能。
结构
- 抽象工厂(Abstract Factory):
定义一个接口,用于创建一系列相关或依赖的产品族。它声明了一组工厂方法,每个方法对应一个产品。 - 具体工厂(Concrete Factory):
实现抽象工厂接口,生产具体产品的实例。每种具体工厂对应于一个产品族。 - 抽象产品(Abstract Product):
为产品族中的产品定义一个公共的接口,确保产品间的一致性和可替换性。 - 具体产品(Concrete Product):
实现抽象产品的接口,是具体工厂生产的产品的类。
使用场景
- 多产品族需求:当需要生产一系列产品,且这些产品之间存在某种关联性或需保持一致的品牌和风格时。
- 系统扩展性:在系统设计时,如果希望将来能够容易地引入新的产品族,而不影响现有代码。
- 解耦产品类:希望将产品类的实例化逻辑与使用产品类的客户端代码分离,以降低耦合度。
- 复杂对象创建:当创建对象的过程较为复杂,涉及多个产品类时,抽象工厂模式可以提供一个统一的创建接口。
优点
产品族一致性
抽象工厂模式确保所创建的产品彼此相关联,形成统一的产品族。这种设计促进了产品间的协调一致性,使得它们能够高效协同工作。
工厂切换灵活性
抽象工厂模式提供了在不同工厂间轻松切换的能力,允许客户端代码根据不同的需求,创建出不同产品族的对象,从而增强了系统的适应性和灵活性。
系统扩展性
当引入新的产品族成为必要时,抽象工厂模式允许通过增加新的具体工厂和产品类来实现,而无需对现有代码进行修改。这不仅促进了系统的扩展,也维护了现有功能的稳定性。
符合开闭原则
遵循开闭原则,抽象工厂模式支持对系统功能的扩展,同时避免了对现有代码的修改。通过简单地添加新的工厂和产品实现,系统功能得以增强而不破坏现有结构。
降低耦合度
抽象工厂模式通过抽象工厂接口,实现了客户端代码与具体产品类的解耦。客户端仅依赖于抽象层的接口定义,而无需深入了解具体产品的实现细节,从而降低了耦合度。
适用于复杂对象构建
当面临需要构建具有内在关联性的复杂产品族的场景时,抽象工厂模式提供了一种系统化和有组织的创建和管理对象的方式,使得对象构建过程更为高效和有序。
缺点
- 增加系统复杂度:每增加一个产品族,都需要增加相应的具体工厂类和产品类,可能导致系统类的数量急剧增加。
- 难以适应变化:如果产品族中的某类产品需要变化,可能需要修改所有的工厂类,这增加了维护难度。
- 不够灵活:对于只生产一种产品的系统,抽象工厂模式可能过于复杂,不如简单工厂模式灵活。
- 难以支持新种类:如果需要添加一个全新的产品种类,不仅需要添加新的具体产品类,还需要扩展抽象工厂接口,这可能涉及到更多的修改。
使用注意事项
- 定义清晰的接口:
- 确保为产品族定义的抽象工厂接口和产品接口是清晰且一致的。
- 避免过度设计:
- 在产品种类不多或产品间没有紧密关联时,避免使用抽象工厂模式,以免增加不必要的复杂性。
- 保持产品族的一致性:
- 确保由同一个工厂创建的产品是协调一致的,可以一起工作。
- 遵循开闭原则:
- 当引入新的产品族时,应通过添加新的工厂和产品类实现,而不是修改现有代码。
- 解耦客户端与具体实现:
- 客户端代码应仅依赖于抽象工厂和产品接口,而不是具体实现。
代码案例
package main
// 定义抽象产品接口,为产品族中的产品定义统一接口
// AbstractPhone 定义了手机的接口
type AbstractPhone interface {
UseA() // 实现产品A的特定功能
}
// AbstractComputer 定义了电脑的接口
type AbstractComputer interface {
UseB() // 实现产品B的特定功能
}
// 创建具体产品类,实现抽象产品接口实现具体产品类
// ConcretePhoneA 是具体手机A的实现
type ConcretePhoneA struct{}
func (p *ConcretePhoneA) UseA() {
println("Phone A is used")
}
// ConcretePhoneB 是具体手机B的实现
type ConcretePhoneB struct{}
func (p *ConcretePhoneB) UseA() {
println("Phone B is used")
}
// ConcreteComputerA 是具体电脑A的实现
type ConcreteComputerA struct{}
func (p *ConcreteComputerA) UseB() {
println("Computer A is used")
}
// ConcreteComputerB 是具体电脑B的实现
type ConcreteComputerB struct{}
func (p *ConcreteComputerB) UseB() {
println("Computer B is used")
}
// 创建抽象工厂类,为创建产品族中的多个产品提供统一的接口
// AbstractFactory 定义了工厂类的接口,用于创建手机和电脑
type AbstractFactory interface {
CreatePhone() AbstractPhone
CreateComputer() AbstractComputer
}
// 创建具体工厂类,实现抽象工厂接口,创建产品族中的多个产品
// ConcreteFactoryA 是具体工厂A,用于创建ConcretePhoneA和ConcreteComputerA
type ConcreteFactoryA struct{}
func (f *ConcreteFactoryA) CreatePhone() AbstractPhone {
return &ConcretePhoneA{}
}
func (f *ConcreteFactoryA) CreateComputer() AbstractComputer {
return &ConcreteComputerA{}
}
// ConcreteFactoryB 是具体工厂B,用于创建ConcretePhoneB和ConcreteComputerB
type ConcreteFactoryB struct{}
func (f *ConcreteFactoryB) CreatePhone() AbstractPhone {
return &ConcretePhoneB{}
}
func (f *ConcreteFactoryB) CreateComputer() AbstractComputer {
return &ConcreteComputerB{}
}
// 客户端代码,通过抽象工厂接口与具体工厂交互,获取所需产品
func main() {
factoryA := &ConcreteFactoryA{}
factoryA.CreatePhone().UseA()
factoryA.CreateComputer().UseB()
facyoryB := &ConcreteFactoryB{}
facyoryB.CreatePhone().UseA()
facyoryB.CreateComputer().UseB()
}