策略模式与简单工厂模式的不同点

 1. 简单工厂模式定义

        简单工厂模式(Simple Factory Pattern)是一种创建型设计模式,它通过专门定义一个类来负责创建其他类的实例,这个类通常被称为工厂类。简单工厂模式并不是一种正式的设计模式,但它确实是一种常用的编程技巧。

        在简单工厂模式中,工厂类包含了一个方法,这个方法根据传入的参数来决定创建哪种具体对象,并返回这个对象的实例。这样做的好处是,将对象创建的逻辑集中管理,客户端代码不需要直接实例化对象,而是通过工厂方法来获取所需的对象。

从上面的定义中可以看出,简单工厂模式包含以下三个部分:

  1. 工厂:负责实现创建所有产品的逻辑,可以说是在这个工厂里面可以实例化所有相关的类;
  2. 产品接口:这里面封装了所有产品的公共方法,这也是一类产品的特性,比如披萨制作过程都会包括:切等等。
  3. 具体产品:一般就是会实现产品接口里面所用公共方法的产品。比如奶酪披萨,素食披萨,他们的制作过程是差不多的,所以都会实现制作披萨这个公共方法。

2. 简单工厂模式UML图表示

2.1 相关代码实现

package simple_factory_pattern


// 产品接口
type Pizza interface {
    MakePizza()
}

package simple_factory_pattern

import "fmt"

// 具体产品---奶酪披萨
type CheesePizza struct{}

func NewCheesePizza() *CheesePizza {
    return &CheesePizza{}
}

func (c *CheesePizza) Prepare() {
    fmt.Println("Prepare Cheese Pizza")
}

func (c *CheesePizza) Bake() {
    fmt.Println("Bake Cheese Pizza")
}

func (c *CheesePizza) Cut() {
    fmt.Println("Cut Cheese Pizza")
}

func (c *CheesePizza) Box() {
    fmt.Println("Box Cheese Pizza")
}

func (c *CheesePizza) MakePizza() {
    c.Prepare()
    c.Bake()
    c.Cut()
    c.Box()
}



package simple_factory_pattern

import "fmt"

// 具体产品2---素食披萨
type VeggiePizza struct{}

func NewVeggiePizza() *VeggiePizza {
    return &VeggiePizza{}
}

func (v *VeggiePizza) Prepare() {
    fmt.Println("Prepare Veggie Pizza")
}

func (v *VeggiePizza) Bake() {
    fmt.Println("Bake Veggie Pizza")
}

func (v *VeggiePizza) Cut() {
    fmt.Println("Cut Veggie Pizza")
}

func (v *VeggiePizza) Box() {
    fmt.Println("Box Veggie Pizza")
}

func (v *VeggiePizza) MakePizza() {
    v.Prepare()
    v.Bake()
    v.Cut()
    v.Box()
}

package simple_factory_pattern

// 披萨工厂,专门用来实例化pizza对象
type PizzaFactory struct{}

// CreatePizza creates a pizza based on the pizzaType
func (p *PizzaFactory) CreatePizza(pizzaType string) Pizza {
    switch pizzaType {
    case "cheese":
       return NewCheesePizza()
    case "veggie":
       return NewVeggiePizza()
    default:
       return nil
    }
}

2.2 优缺点

简单工厂模式的优点包括:

  • 客户端代码与具体类的实现解耦,便于后期的扩展和维护。

  • 中央化了对象创建的逻辑,使代码更易读、更易管理。

缺点包括:

  • 工厂类集中了所有实例创建的逻辑,可能会导致该类变得过于复杂

  • 增加新的产品类型时需要修改工厂类的代码,违背了开闭原则(对扩展开放,对修改关闭)。

3. 策略模式概念定义

        策略模式是一种行为型设计模式,它定义了一系列算法,并将每一个算法封装起来,使它们可以互相替换,从而让算法的变化不会影响到使用算法的客户。策略模式使得算法可以在不影响客户端的情况下发生变化。

        在策略模式中,我们将不同的算法封装在独立的类中,称为策略类。每一个策略类实现一个共同的接口,这样可以在运行时通过该接口来调用具体的算法

策略模式的主要角色有:

  1. 策略接口(Strategy):这是一个接口,定义了算法的公共方法。

  2. 具体策略类(Concrete Strategy):实现策略接口的具体类,每个类封装了一种算法。

  3. 上下文类(Context):持有一个策略接口的引用,它可以动态地更换策略。

4. 策略模式使用场景

策略模式适用于以下几种场景:

  1. 多个算法可以互换: 当一个系统需要在运行时动态地选择其中一个算法时,策略模式是非常适用的。例如,支付系统可能需要支持多种支付方式,如信用卡支付、支付宝支付和微信支付

  2. 算法的变化独立于使用算法的客户端: 当算法的实现细节需要对客户端隐藏时,通过策略模式可以将算法封装在独立的策略类中,从而使得客户端代码与具体的算法实现解耦。

  3. 避免使用多重条件语句(如 if-elseswitch-case: 当多个条件语句控制着许多不同的行为时,可以将这些行为移到策略类中,以避免多重条件语句,使代码更可读和更易维护。

  4. 需要灵活地替换和复用算法时: 当系统中的某个行为有很多种实现方式,并且这些实现方式需要灵活地互相替换时,可以使用策略模式。

  5. 需要根据不同的环境或条件动态地选择算法时: 当算法的选择依赖于某些特定的条件或环境时,策略模式可以让这些条件或环境动态地决定使用哪种策略。

以下是几个具体的应用场景:

  1. 排序算法: 一个系统可以支持多种排序算法(如快速排序、归并排序、插入排序等),策略模式可以让系统在运行时选择合适的排序算法。

  2. 数据压缩: 一个文件压缩系统可以支持多种压缩算法(如 ZIP、RAR、GZIP 等),策略模式可以让用户选择所需的压缩算法。

  3. 路径查找: 在地图应用中,可以使用不同的路径查找算法(如最短路径、最少收费路径等),策略模式可以让用户选择不同的路径查找策略。

  4. 日志记录: 一个日志系统可以支持多种日志记录方式(如文件日志、数据库日志、远程日志等),策略模式可以让系统在运行时选择合适的日志记录策略。

  5. 促销活动: 电子商务系统中的促销活动可能有多种计算方式(如满减、打折、积分兑换等),通过策略模式可以灵活地切换不同的促销策略。

通过使用策略模式,可以使系统具有更好的扩展性和灵活性,能够更容易地应对变化和扩展需求。

3. 简单代码实现【策略模式实现一个系统支持多种压缩策略】

// 上下文类

package strategy

/*
策略模式上下文类:
    1. 通过上下文类选择具体的策略
    2. 通过上下文类执行具体的策略
*/

type CompressContext struct {
    compressor Compressor
}

// SetCompressor 通过上下文类选择具体的策略
func (c *CompressContext) SetCompressor(compressor Compressor) {
    c.compressor = compressor
}

// CompressFile 通过上下文类执行具体的策略
func (c *CompressContext) CompressFile(file string) string {
    if c.compressor == nil {
       return "No compression algorithm selected"
    }
    return c.compressor.Compress(file)
}


// 策略接口
package strategy

// Compressor 是一个压缩接口,定义了压缩方法
type Compressor interface {
    Compress(file string) string
}


// 具体策略
package strategy

type ZipCompressor struct{}

func (z *ZipCompressor) Compress(file string) string {
    return file + ".zip"
}


package strategy

// RarCompressor 实现了 Compressor 接口
type RarCompressor struct{}

func (r *RarCompressor) Compress(file string) string {
    return file + ".rar"
}

package strategy

// GzipCompressor 实现了 Compressor 接口
type GzipCompressor struct{}

func (g *GzipCompressor) Compress(file string) string {
    return file + ".gz"
}


// 客户端实现,运行时换策略
func main() {
    file := "test.txt"
    context := &strategy.CompressContext{}

    // 以下属于运行时修改策略
    // 选择策略gzip
    context.SetCompressor(&strategy.GzipCompressor{})
    fmt.Println(context.CompressFile(file))

    // 选择策略zip
    context.SetCompressor(&strategy.ZipCompressor{})
    fmt.Println(context.CompressFile(file))

    // 选择策略rar
    context.SetCompressor(&strategy.RarCompressor{})
    fmt.Println(context.CompressFile(file))
}

 5. 优缺点

策略模式的优点包括:

  • 可以在运行时更改对象的行为。

  • 可以避免使用多重条件语句(如 if-elseswitch-case),使代码更简洁。

  • 符合开闭原则(对扩展开放,对修改关闭),添加新算法时只需要添加新的策略类,而无需修改现有代码。

缺点包括:

  • 客户端必须了解所有的策略类,以便选择合适的策略。

  • 可能会增加系统中类的数量,导致代码复杂度增加。

6. 策略模式与简单工厂模式的不同点

从上面的说明来看,可以总结为以下三点:

  • 目的不同

    • 策略模式的目的是让算法可以互换,且客户端可以在运行时选择不同的策略。

    • 简单工厂模式的目的是简化对象的创建过程,将创建对象的逻辑集中到一个工厂类中。

  • 灵活性和扩展性

    • 策略模式更灵活,可以在不修改现有代码的前提下增加新的策略。

    • 简单工厂模式相对不太灵活,增加新产品时需要修改工厂类。

  • 使用时机

    • 策略模式适用于算法需要频繁变化或者需要在运行时选择不同算法的情景。

    • 简单工厂模式适用于对象创建过程复杂且变化不频繁的情景。 

举个不怎么恰当的例子可以加深理解:

简单工厂模式就好比如:把一个轮船在一个指定的流水线生产出来,后续用于载人,载物都可以,该工厂是不会管的,属于是一种创建的模式;【注重的是简化创建过程,可以理解为静态的,变化不频繁】

策略模式就好比如:在旅行的途中,遇到水路我可以选择坐轮船,也可以选择坐飞机,可以随意选择,遇到陆地,我可以选择打车,也可以选择走路。属于是一种自主选择的行为。【注重的是简化切换过程,动态的,切换比较频繁】

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

SAO&asuna

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值