Golang设计模式(一)简单工厂 工厂方法 抽象工厂

简单工厂

什么是简单工厂

定义一个工厂类,它可以根据参数的不同返回不同类的实例,被创建的实例通常都具有共同的父类。

基本流程

  1. 定义产品接口
    • 创建一个抽象的产品类或接口,定义产品的共同特征。
  2. 实现具体产品类
    • 实现一个或多个具体产品类,它们继承自产品接口或抽象类,具体化产品接口的抽象方法。
  3. 定义工厂接口
    • 设计一个工厂类,它包含一个或多个方法,用于创建不同类型的产品对象。
  4. 实现工厂方法
    • 在工厂类中实现创建产品对象的逻辑。通常,这个方法会根据输入参数来决定创建哪种具体产品对象。
  5. 客户端调用
    • 客户端代码通过调用工厂类的工厂方法,并传入必要的参数,以获取所需的产品对象。
  6. 返回产品对象
    • 工厂方法根据传入的参数创建相应的具体产品对象,并将其返回给客户端。
  7. 使用产品对象
    • 客户端使用返回的产品对象执行所需的操作,而无需关心对象的具体创建细节。

结构

**工厂:**创建对象,创建产品实例的内部逻辑,外部不感知。外部直接调用,创建所需的产品对象

**产品:**所有对象的公共方法,也就是父类。内部方法只声明不定义。

具体产品: 具体产品的公共方法的具体实现。

使用场景

  • 对象种类有限:当需要创建的对象种类较少时,使用简单工厂模式可以保持工厂方法的业务逻辑简洁,避免复杂化。
  • 客户端解耦:客户端仅需要了解如何传递正确的参数给工厂类,而无需关心对象的具体创建过程。这降低了客户端与对象创建逻辑之间的耦合度。
  • 简化客户端代码:在对象创建逻辑较为直接时,客户端不需要了解对象的具体类型或创建细节,只需与工厂类交互即可获得所需的对象。
  • 创建逻辑透明化:客户端不需要了解对象是如何被创建和组装的,只需关注如何使用工厂类提供的接口来获取对象。
  • 对象创建灵活性:当系统需要灵活地创建一系列相关或相互依赖的对象时,简单工厂模式提供了一种集中管理和扩展的简便方式

优点

  1. 封装性:隐藏了对象创建的复杂性,客户端不需要知道具体的创建细节。
  2. 客户端解耦:客户端与具体产品类解耦,只需与工厂类交互。
  3. 可维护性:当需要添加新的产品时,只需扩展工厂类,不需要修改客户端代码。
  4. 简单性:在对象创建逻辑相对简单且对象种类有限的情况下,实现容易理解。

缺点

  1. 扩展性限制:如果产品类的数量非常多,工厂方法中的业务逻辑将变得复杂。
  2. 紧耦合:工厂类与产品类之间存在紧密耦合,一旦产品类变化,工厂类也需要相应修改。
  3. 增加系统的复杂度:随着产品种类的增加,工厂类的方法数量和复杂度也会增加。
  4. 难以形成框架:由于工厂类集中了所有产品类的创建逻辑,这可能使得形成更高层次的框架变得困难。

使用注意事项

  1. 明确职责:确保工厂类职责清晰,避免将非创建逻辑的业务代码放入工厂类中。
  2. 避免过度集中:如果工厂类变得过于复杂,考虑使用其他创建型模式,如工厂方法模式或抽象工厂模式。
  3. 扩展性考虑:设计时考虑未来可能的扩展,确保工厂类能够容易地添加新产品。
  4. 单一职责原则:工厂类应该只负责对象的创建,遵循单一职责原则。
  5. 使用接口引用:客户端应该通过抽象产品类的接口引用产品,而不是具体产品类的实例。
  6. 避免暴露实现:不要在工厂类中暴露具体的产品类实现,以保持系统的灵活性和可维护性。

代码实例

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()
}

工厂方法模式

什么是工厂模式

在简单工厂模式下只提供一个工厂类,该工厂处于对产品类进行实例化的中心位置,它需要知道每个产品对象的创建细节,并决定何时实例化哪个产品类,当有新产品加入时,必须修改工厂类

工厂方法模式:定义一个用于创建对象的接口,让子类决定将哪个类实例化。不再提供一个统一的工厂类来创建所有的产品对象,针对不同的产品提供不同的工厂。提供一个抽象工厂接口来声明抽象工厂方法,而由其子类来具体实现工厂方法,创建具体的产品对象。适用于需要将对象创建过程封装起来,同时提供系统扩展性的场景。

基本流程

  1. 定义产品接口
    创建一个产品接口,定义了所有具体产品对象的公共接口。
  2. 创建具体产品类
    实现产品接口,为每一个具体产品提供实现。
  3. 定义工厂接口
    创建一个工厂接口,用于定义创建产品的方法。
  4. 实现具体工厂类
    为每一个具体工厂类提供工厂接口的实现,每个具体工厂类只能创建一个具体产品。
  5. 客户端使用
    客户端通过工厂接口与具体工厂类交互,获取所需的产品对象,而无需知道具体的产品类。

结构

  • 工厂:不在实现创建所有的具体产品实例,只声明一个创建接口,具体初始化动作交给具体工厂
  • 具体工厂:实现工厂的方法,返回一个具体产品的实例
  • 产品:所有对象的公共方法,也就是父类。内部方法只声明不定义。
  • 具体产品:由具体工厂创建,实现父类方法

使用场景

  • 当系统需要在运行时根据不同条件创建不同类的实例时。
  • 当一个类不知道它必须创建的实例的具体类时。
  • 当需要让系统的扩展更加容易,不修改现有代码的情况下引入新的类时。
  • 在实际使用时,具体工厂类在实现工厂方法时除了创建具体产品对象之外,还可以负责产品对象的初始化工作以及一些资源和环境配置工作,例如连接数据库、创建文件等。
  • 遵循开闭原则:当需要添加新产品时,只需添加相应的具体工厂类和产品类,而无需修改现有的工厂类和产品类代码,这符合软件设计的开闭原则(对扩展开放,对修改封闭)。

优点

  1. 封装性
    工厂方法模式隐藏了对象创建的具体细节,使得客户端不需要知道具体的类是如何实现的。
  2. 扩展性
    当需要引入新的类时,只需添加相应的具体类和相应的具体工厂类,无需修改已有代码。
  3. 解耦
    工厂方法模式将对象的创建和使用分离,降低了模块间的耦合度。
  4. 代码复用
    可以在类的层次结构中引入新的类,而不影响其他对象的使用。

缺点

  1. 增加系统复杂度
    每增加一个产品类别,都需要增加一个具体类和对象的具体工厂类,这可能会导致系统中类的数量急剧增加。
  2. 增加系统的抽象性
    在添加新的产品类时,需要对工厂方法的接口进行扩展,这增加了系统的抽象性和理解难度。
  3. 增加系统的重量
    工厂方法模式增加了额外的工厂类,这可能会使系统变得庞大。

使用注意事项

  1. 定义清晰的接口
    确保产品接口和工厂接口清晰明确,易于理解和使用。
  2. 避免过度扩展
    考虑系统的扩展性,但也要避免过度设计,引入不必要的复杂性。
  3. 保持一致性
    所有具体工厂类应该遵循相同的接口,以保持一致性。

代码实例

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模式,它是一种对象创建型模式。

基本流程

  1. 定义抽象产品
    为每个产品族定义一个抽象产品类或接口。
  2. 实现具体产品
    为每个抽象产品提供一个或多个具体实现。
  3. 定义抽象工厂
    创建一个抽象工厂接口,声明一组方法,用于创建各种抽象产品。
  4. 实现具体工厂
    为每个产品族提供一个具体工厂类,实现抽象工厂接口,并创建具体的产品。
  5. 客户端使用
    客户端通过抽象工厂接口与具体工厂类交互,请求创建产品族中的一个或多个产品。
  6. 获取产品
    具体工厂根据请求创建并返回具体产品实例。
  7. 产品使用
    客户端使用返回的产品实例,完成所需的功能。

结构

  1. 抽象工厂(Abstract Factory)
    定义一个接口,用于创建一系列相关或依赖的产品族。它声明了一组工厂方法,每个方法对应一个产品。
  2. 具体工厂(Concrete Factory)
    实现抽象工厂接口,生产具体产品的实例。每种具体工厂对应于一个产品族。
  3. 抽象产品(Abstract Product)
    为产品族中的产品定义一个公共的接口,确保产品间的一致性和可替换性。
  4. 具体产品(Concrete Product)
    实现抽象产品的接口,是具体工厂生产的产品的类。

使用场景

  • 多产品族需求:当需要生产一系列产品,且这些产品之间存在某种关联性或需保持一致的品牌和风格时。
  • 系统扩展性:在系统设计时,如果希望将来能够容易地引入新的产品族,而不影响现有代码。
  • 解耦产品类:希望将产品类的实例化逻辑与使用产品类的客户端代码分离,以降低耦合度。
  • 复杂对象创建:当创建对象的过程较为复杂,涉及多个产品类时,抽象工厂模式可以提供一个统一的创建接口。

优点

产品族一致性

抽象工厂模式确保所创建的产品彼此相关联,形成统一的产品族。这种设计促进了产品间的协调一致性,使得它们能够高效协同工作。

工厂切换灵活性

抽象工厂模式提供了在不同工厂间轻松切换的能力,允许客户端代码根据不同的需求,创建出不同产品族的对象,从而增强了系统的适应性和灵活性。

系统扩展性

当引入新的产品族成为必要时,抽象工厂模式允许通过增加新的具体工厂和产品类来实现,而无需对现有代码进行修改。这不仅促进了系统的扩展,也维护了现有功能的稳定性。

符合开闭原则

遵循开闭原则,抽象工厂模式支持对系统功能的扩展,同时避免了对现有代码的修改。通过简单地添加新的工厂和产品实现,系统功能得以增强而不破坏现有结构。

降低耦合度

抽象工厂模式通过抽象工厂接口,实现了客户端代码与具体产品类的解耦。客户端仅依赖于抽象层的接口定义,而无需深入了解具体产品的实现细节,从而降低了耦合度。

适用于复杂对象构建

当面临需要构建具有内在关联性的复杂产品族的场景时,抽象工厂模式提供了一种系统化和有组织的创建和管理对象的方式,使得对象构建过程更为高效和有序。

缺点

  • 增加系统复杂度:每增加一个产品族,都需要增加相应的具体工厂类和产品类,可能导致系统类的数量急剧增加。
  • 难以适应变化:如果产品族中的某类产品需要变化,可能需要修改所有的工厂类,这增加了维护难度。
  • 不够灵活:对于只生产一种产品的系统,抽象工厂模式可能过于复杂,不如简单工厂模式灵活。
  • 难以支持新种类:如果需要添加一个全新的产品种类,不仅需要添加新的具体产品类,还需要扩展抽象工厂接口,这可能涉及到更多的修改。

使用注意事项

  1. 定义清晰的接口
    • 确保为产品族定义的抽象工厂接口和产品接口是清晰且一致的。
  2. 避免过度设计
    • 在产品种类不多或产品间没有紧密关联时,避免使用抽象工厂模式,以免增加不必要的复杂性。
  3. 保持产品族的一致性
    • 确保由同一个工厂创建的产品是协调一致的,可以一起工作。
  4. 遵循开闭原则
    • 当引入新的产品族时,应通过添加新的工厂和产品类实现,而不是修改现有代码。
  5. 解耦客户端与具体实现
    • 客户端代码应仅依赖于抽象工厂和产品接口,而不是具体实现。

代码案例

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()
} 

  • 19
    点赞
  • 12
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值