go

golang工厂模式

介绍

工厂模式是一种创建型设计模式,它提供了一种统一的接口来创建对象,而无需暴露对象的创建逻辑。工厂模式可以帮助我们降低代码的耦合性。根据业务场景可以分为:简单工厂模式(Simple Factory Pattern)、工厂方法模式(Factory Method Pattern)和抽象工厂模式(Abstract Factory Pattern)。

简单工厂模式

定义一个工厂类,它可以根据客户端传入的参数的不同,创建并返回相应的对象实例,被创建的实例通常都具有共同的父类。因为在简单工厂模式中用于创建实例的方法是静态(static)方法,因此简单工厂模式又被称为静态工厂方法(Static Factory Method)模式。简单工厂模式包含以下角色:

  • 工厂(Factory):负责创建具体产品的工厂类,通常包含一个静态方法来创建产品对象。
  • 产品接口(Product):定义了产品的接口,通常包含一些公共的方法。
  • 具体产品(Concrete Product):实现了抽象产品接口,具体产品由具体工厂创建。

下面是一个代码示例:

package main

import "fmt"

// 创建Ball产品类,包括Play()方法
type Ball interface {
    Play()
}

// 创建BasketBall和Football产品类,都实现了Ball接口
type BasketBall struct{}

func (b *BasketBall) Play() {
    fmt.Println("playing basketball")
}

type Football struct{}

func (f *Football) Play() {
    fmt.Println("playing football")
}

// 创建PlayBall工厂类,用于创建BasketBall和Football,即产品对象
type PlayBall struct{}

func (p *PlayBall) CreateBall(ballname string) Ball {
    switch ballname {
    case "basketball":
        return &BasketBall{}
    case "football":
        return &Football{}
    default:
        return nil
    }
}
// 在客户端代码中,通过工厂类创建产品对象,然后调用产品对象的Play()方法
func main() {
    pb := &PlayBall{}
    b := pb.CreateBall("basketball")
    b.Play()
    b = pb.CreateBall("football")
    b.Play()
}

优点

  • 在工厂类中,根据客户端传入的参数,决定创建哪种类型的产品对象。客户端只需要调用工厂类的方法,无需关心具体的产品创建细节。
  • 也可以引入配置文件,在不修改客户端代码的情况下更换和添加新的具体产品类。

缺点

  • 简单工厂模式的工厂类单一,负责所有产品的创建,职责过重,一旦异常,整个系统将受影响。且工厂类代码会非常臃肿,违背高内聚原则。
  • 使用简单工厂模式会增加系统中类的个数(引入新的工厂类),增加系统的复杂度和理解难度。
  • 系统扩展困难,一旦增加新产品不得不修改工厂逻辑,在产品类型较多时,可能造成逻辑过于复杂。

适用场景

  • 当需要创建的对象较少且对象之间的创建逻辑相对简单时。
  • 当客户端不需要知道对象的创建细节,只需要知道如何使用对象时。
  • 当需要对创建对象的过程进行集中管理时。

例如:

  • 客户根据需要选择车型,工厂根据车型生产对应的车辆;
  • 客户告诉店家想要点的菜,店家根据客户的需求制作相应的菜品。

工厂方法模式

工厂方法模式属于创建型设计模式,它将对象的创建延迟到子类中进行,通过定义一个创建对象的接口,让子类决定实例化哪个类。工厂方法模式包含四个主要角色:

  • 抽象产品(Product):定义了产品的接口。
  • 具体产品(ConcreteProduct):实现了具体的产品逻辑。
  • 抽象工厂(Factory):定义了创建产品的接口。
  • 具体工厂(ConcreteFactory):实现了具体的产品创建逻辑。

下面是一个代码示例:

package main

import "fmt"

// 定义抽象产品接口Ball,包括Play()方法
type Ball interface {
    Play()
}

// 定义具体产品类BasketBall和Football,都实现了Ball接口
type Football struct{}

func (f *Football) Play() {
    fmt.Println("playing football")
}

type Basketball struct{}

func (b *Basketball) Play() {
    fmt.Println("playing basketball")
}

// 定义抽象工厂类PlayBall,包含了创建产品的抽象方法CreateBall()
type PlayBall interface {
    CreateBall() Ball
}

// 定义具体工厂类Fball和Bball,他们分别实现了PlayBall接口
type Fball struct{}

func (f *Fball) CreateBall() Ball {
    return &Football{}
}

type Bball struct{}

func (b *Bball) CreateBall() Ball {
    return &Basketball{}
}

// 在客户端代码中,通过工具体工厂类创建产品对象,然后调用产品对象的Play()方法
func main() {
    f := &Fball{}
    fb := f.CreateBall()
    fb.Play()
    b := &Bball{}
    bb := b.CreateBall()
    bb.Play()
}

优点

  • 新增具体产品时无需修改现有代码,只需要添加新的具体工厂和具体产品即可,易于扩展。
  • 解耦了对产品的操作,每种操作都作为一种工厂类,做到了工厂隔离。客户端无需直接依赖具体产品类,从而降低了与具体产品的耦合性。

缺点

  • 增加了类的个数,将产品的创建过程封装在具体工厂中,增加了系统的抽象性和理解难度。
  • 不支持新增产品族。在新增产品族时,需要同时新增对应的具体工厂类,增加了系统的复杂度。

使用场景

  • 当一个类不知道它所必须创建的对象的类时,将对象的创建交给具体的工厂类处理。
  • 当一个类希望由它的子类来指定创建对象时,将对象的创建延迟到子类中实现。
  • 当客户端需要根据不同的条件来创建不同类型的对象时。
  • 当系统需要扩展以支持新的产品时。

例如:

  • 每个车间负责生产特定型号的汽车,不同型号的车辆由不同的车间负责制造。用户选择型号就可以买到对应的车。
  • 每种菜系都有对应的厨师,用户选择菜品就可以吃到对应的菜。

抽象工厂模式

抽象工厂模式属于创建型设计模式,它提供了一种封装一组相关对象创建的方式,而无需指定具体的类。抽象工厂模式包含四个主要角色:

  • 抽象工厂(AbstractFactory):抽象工厂是一个接口或抽象类,它声明了一组用于创建不同产品族的抽象工厂方法。这些工厂方法返回抽象产品对象。抽象工厂定义了一族产品的创建接口。
  • 具体工厂(ConcreteFactory):具体工厂是实现了抽象工厂接口的具体类,它负责实现抽象工厂接口中的工厂方法。每个具体工厂负责创建特定的产品族。具体工厂根据具体的业务逻辑,创建产品的具体实例。
  • 抽象产品(AbstractProduct):定义了产品的接口
  • 具体产品(ConcreteProduct):实现了具体的产品逻辑。

下面是一个代码示例:

package main

import "fmt"

// 定义抽象产品类Game,包含抽象方法Playing()
type Game interface {
    Playing()
}

// 创建具体产品类YuanShen和Lol,他们都实现了Playing()接口
type YuanShen struct{}

func (p *YuanShen) Playing() {
    fmt.Println("playing yuanShen")
}

type Lol struct{}

func (c *Lol) Playing() {
    fmt.Println("playing lol")
}

// 定义抽象工厂类PlayGame,包含两个抽象方法CreateYuanShen(),CreateLol()
type PlayGame interface {
    CreateYuanShen() Game
    CreateLol() Game
}

// 创建具体工厂类MobileFactory和ComputerFactory,他们都实现了PlayGame接口
type MobileFactory struct{}

func (p *MobileFactory) CreateYuanShen() Game {
    return &YuanShen{}
}

func (p *MobileFactory) CreateLol() Game {
    return &Lol{}
}

type ComputerFactory struct{}

func (c *ComputerFactory) CreateYuanShen() Game {
    return &YuanShen{}
}

func (c *ComputerFactory) CreateLol() Game {
    return &Lol{}
}

// 在客户端中,调用工厂类的CreateYuanShen()和CreateLol()方法来创建具体的产品对象
func main() {
    mobileFactory := &MobileFactory{}
    mobileFactory.CreateYuanShen().Playing()
    mobileFactory.CreateLol().Playing()

    computerFactory := &ComputerFactory{}
    computerFactory.CreateYuanShen().Playing()
    computerFactory.CreateLol().Playing()
}

优点

  • 客户端只需要使用具体工厂类来创建产品对象,无需关心具体的产品创建细节,降低了与具体产品的耦合性。
  • 所有被创建的产品都属于同一种产品族,保持了产品的内部一致性。
  • 支持创建产品族。只需要添加新的具体工厂和具体产品即可,而不需要修改现有代码。易于扩展。

缺点

  • 增加了类的个数,将产品的创建过程封装在具体工厂中,增加了系统的抽象性和理解难度。
  • 不支持新增产品。在新增单个产品时,需要同时新增对应的抽象产品、具体产品和具体工厂类,增加了系统的复杂度。

使用场景

  • 当需要创建一族相关或相互依赖的产品对象时
  • 当希望客户端代码与具体产品的实现解耦,只关注产品的接口时
  • 当系统需要在运行时切换不同产品族时
  • 当需要提供一组相关产品的接口,而不关心具体实现时

例如:

  • 不同的汽车制造商生产不同的汽车,每个汽车又包括不同的功能,用户选择车的型号就可以获得对应的功能。
  • 饭店里多名厨师,每个厨师会做不同的菜,用户选择菜品就可以吃到对应的菜。
分类: go
0 0 投票数
文章评分
订阅评论
提醒
guest

0 评论
内联反馈
查看所有评论

相关文章

开始在上面输入您的搜索词,然后按回车进行搜索。按ESC取消。

返回顶部
0
希望看到您的想法,请您发表评论x