前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >Go语言设计模式,这样用简直不要太爽!

Go语言设计模式,这样用简直不要太爽!

作者头像
FunTester
发布2023-08-04 11:58:12
2250
发布2023-08-04 11:58:12
举报
文章被收录于专栏:FunTesterFunTester

【内容概览】

1. 为什么需要设计模式

2. 实战示例

1)什么是工厂方法模式

2)工厂方法模式的使用场景

3)工厂方法模式的实现方式

4)Go语言实战

5)工厂方法模式的优缺点

01

为什么需要设计模式

设计模式可以根据以前的实践和经验记录要采用的解决方案。

在设计模式的实现过程中,需要使用多个软件组件共同实现某些功能。

因此,设计模式加快了涉及多个组件的开发过程。

开发者可以在对应解决方案的具体应用中使用熟悉的编程语言。

例如,如果某个开发者熟悉Go语言,那么这个开发者可以使用Go语言开发相应的组件。

  • 使用设计模式可以提高开发速度。设计模式提供了经过验证的开发范例,有助于节省时间,而不必在每次出现问题时都重新创建设计模式。
  • 因为设计模式是为了修复已知问题而创建的,所以设计模式可以在软件开发过程中对其进行预测。
  • 使用设计模式可以提高开发者的思维能力、编程能力和设计能力。
  • 设计模式使程序设计更加标准化、代码编制更加工程化,从而提高软件的开发效率,缩短软件的开发周期。
  • 使用设计模式设计的代码可重用性高、可读性强、可靠性高、灵活性好、可维护性强。设计模式可以在多种情况下以具体方式使用,可以让系统在后期更容易维护和扩展。

02

实战示例
1)什么是工厂方法模式

工厂方法模式(Factory Method Pattern)定义了一个用于创建对象的接口,但让子类决定实例化哪个类。

接口中的工厂方法允许类将实例化操作推迟到一个或多个具体子类中。

工厂方法模式是创建对象的最佳方法之一,其中的对象创建逻辑对客户端隐藏。

工厂方法模式的UML类图如下图所示。

根据上图可知,工厂方法模式的角色组成如下。

  • 工厂(Factory):声明返回产品对象的工厂方法的接口。该方法返回的对象类型必须与产品接口类型相匹配。
  • 具体工厂(ConcreteFactory):实现工厂接口的类,会重写基础工厂方法,使其返回不同类型的产品。
  • 产品(Product):声明产品方法的接口。对于所有由具体工厂类及其子类构建的对象,该接口是通用的。
  • 具体产品(ConcreteProduct):实现产品接口的类。
2)工厂方法模式的使用场景
  • 在程序开发过程中,如果开发者无法预知对象的具体类型及其依赖关系,则可以使用工厂方法模式。工厂方法模式将创建产品的工厂代码与产品代码分离,从而降低代码之间的耦合度。例如,如果需要添加一种新产品,则只需创建一个新的具体工厂类,然后重写其工厂方法。
  • 如果开发者希望其他开发者可以扩展软件库或框架的内部组件,则可以使用工厂方法模式。
  • 如果一个类需要通过子类指定其创建的对象,则可以使用工厂方法模式。
3)工厂方法模式的实现方式

(1)定义工厂接口。

在工厂方法模式中,会在工厂接口中声明对所有产品都有意义的方法,示例代码如下:

代码语言:javascript
复制
//工厂接口
type Factory interface {
    FactoryMethod(owner string) Product
}

(2)定义具体工厂类,并且实现工厂接口中的方法。

示例代码如下:

代码语言:javascript
复制
//具体工厂类
type ConcreteFactory struct {


}


//具体工厂类的工厂方法
func (cf *ConcreteFactory) FactoryMethod(owner string) Product {
    p := &ConcreteProduct{}
    return p
}

在具体工厂类的工厂方法中调用具体产品对象,并且返回具体产品对象。开发者可能需要在工厂方法中添加临时参数,用于控制返回的具体产品对象的类型。

(3)定义产品接口,并且定义该接口中的方法签名。

示例代码如下:

代码语言:javascript
复制
//产品接口
type Product interface {
    Use()
}

(4)定义具体产品类,并且实现产品接口中的方法。

示例代码如下:

代码语言:javascript
复制
//具体产品类
type ConcreteProduct struct {
} 


//具体产品类的方法
func (p *ConcreteProduct) Use()  {
    fmt.Println("This is a concrete product")
}

(5)创建客户端,使用工厂生产产品。

示例代码如下:

代码语言:javascript
复制
package main


import (
    "github.com/shirdonl/goDesignPattern/chapter2/factory/example"
)


func main() {
    //声明具体工厂对象
    factory := example.ConcreteFactory{}


    //生产产品
    product := factory.FactoryMethod("shirdon")
    //使用产品
    product.Use()
}
//$ go run main.go
//This is a concrete product
4)Go语言实战

假设开发者正在开发一款服装工厂的品牌管理应用程序。

该应用程序的最初版本只能生产一种品牌ANTA的服装,因此大部分代码都在位于名为ANTA的类中。在一段时间后,工厂生产的这个品牌的服装质量很好,销量很高。工厂收到了很多其他公司的合作请求,希望工厂能够生产其他品牌的服装。

在应用程序中新增一个品牌类会遇到问题。如果其他代码与现有的类已经存在耦合关系,那么向应用程序中添加新类会比较麻烦。

目前,大部分代码都与ANTA类有关。如果要在应用程序中添加新的品牌类PEAK,则需要修改之前编写的大部分代码。

此外,如果开发者以后需要在程序中添加其他品牌类,则需要再次对代码进行大规模修改。

使用工厂方法模式可以解决上面的问题。工厂方法模式建议使用特殊的工厂方法调用对象,工厂方法返回的对象通常称为产品。

在工厂方法模式中,开发者可以在子类中重写工厂方法,从而改变其创建的产品类型。

工厂方法模式的UML类图如下图所示。

所有产品都必须实现同一个接口。例如,PEAK类和ANTA类都必须实现服装产品接口IClothes,该接口中声明了方法GetName()和GetSize()。只要产品类实现一个共同的产品接口,开发者就可以将其对象传递给客户端,不需要提供其他数据。

客户端不需要了解不同子类返回的对象之间的差别。客户端将所有产品视为抽象的服装产品接口IClothes。客户端知道所有服装品牌对象都有其相应的方法,无须关心服装品牌对象的具体实现方式。

由于Go语言中缺少类和继承等面向对象编程的特性,因此无法使用Go语言实现经典的工厂方法模式。不过,开发者仍然可以实现工厂方法模式的基础版本,即简单工厂。在本实战中,开发者会使用服装工厂类生产多种品牌的服装。

首先,创建一个名为IClothes的接口,在该接口中定义生产一套服装所需的所有方法;然后,创建实现IClothes接口的服装产品类clothes。

有两种具体的服装产品类,分别是ANTA类与PEAK类,二者都嵌入了clothes类,并且间接实现了IClothes接口中的所有方法。

服装工厂类ClothesFactory会发挥工厂的作用,即通过传入参数生产所需类型的服装。main.go文件会扮演客户端的角色,它不会直接与ANTA类或PEAK类进行互动,而是依靠ClothesFactory类创建多种服装产品对象,仅使用字符参数控制生产。

(1)定义服装产品接口IClothes,该接口中有两个私有方法——setName()和setSize(),以及两个公共方法——GetName()和GetSize(),代码如下:

代码语言:javascript
复制
type IClothes interface {
    setName(name string)
    setSize(size int)
    GetName() string
    GetSize() int
}

(2)定义服装产品类clothes及其方法,该类会被嵌套进PEAK、ANTA等具体品牌类,代码如下:

代码语言:javascript
复制
type clothes struct {
    name  string
    size int
}


func (c *clothes) setName(name string) {
    c.name = name
}


func (c *clothes) GetName() string {
    return c.name
}


func (c *clothes) setSize(size int) {
    c.size = size
}


func (c *clothes) GetSize() int {
    return c.size
}

(3)定义具体服装产品类PEAK及其初始化函数,代码如下:

代码语言:javascript
复制
type PEAK struct {
    clothes
}


func newPEAK() IClothes {
    return &PEAK{
        clothes: clothes{
            name:  "PEAK clothes",
            size: 1,
        },
    }
}

(4)定义具体服装产品类ANTA及其初始化函数,代码如下:

代码语言:javascript
复制
type ANTA struct {
    clothes
}


func newANTA() IClothes {
    return &ANTA{
        clothes: clothes{
            name:  "ANTA clothes",
            size: 4,
        },
    }
}

(5)编写MakeClothes()函数,该函数会根据实参类型生产不同品牌的服装,代码如下:

代码语言:javascript
复制
func MakeClothes(clothesType string) (IClothes, error) {
    if clothesType == "ANTA" {
        return newANTA(), nil
    }
    if clothesType == "PEAK" {
        return newPEAK(), nil
    }
    return nil, fmt.Errorf("Wrong clothes type passed")
}

(6)创建客户端,测试工厂方法模式,代码如下:

代码语言:javascript
复制
func main() {
    ANTA, _ := pkg.MakeClothes("ANTA")
    PEAK, _ := pkg.MakeClothes("PEAK")


    printDetails(ANTA)
    printDetails(PEAK)
}


func printDetails(c pkg.IClothes) {
    fmt.Printf("Clothes: %s", c.GetName())
    fmt.Println()
    fmt.Printf("Size: %d", c.GetSize())
    fmt.Println()
}
//$ go run main-actual-combat.go
//Clothes: ANTA clothes
//Size: 4
//Clothes: PEAK clothes
//Size: 1
5)工厂方法模式的优缺点

优点:

  • 应用程序的模块具有可扩展性。在工厂方法模式中,调用一个方法与新类的实现是完全分离的。这种情况对如何扩展软件有特殊的影响:工厂方法具有高度的自治性,开发者在添加新类后,无须以任何方式更改应用程序。
  • 工厂组件具有单独可测试性。例如,如果工厂方法模式实现了3个类,则可以单独测试每个类的功能。
  • 与类的构造函数或初始化函数不同,可以为工厂方法起一个有意义的名称。

缺点:

  • 系统中类的数量会成对增加,从而提高系统的复杂度。工厂设计模式的实现会导致集成类的数量大幅增加,因为每个具体产品类都需要一个具体工厂类。尽管工厂方法模式有利于软件扩展,但会增加工作量。如果要扩展工厂方法模式的产品系列,则必须调整工厂接口及相应的具体工厂类。因此,针对所需产品类型提前进行可靠规划是必不可少的。
  • 抽象层的引入,提高了开发者对系统的理解难度。在客户端代码中需要使用抽象层,提高了系统的抽象性和开发者的理解难度。

以上节选自《Go语言设计模式》一书。

本书聚焦于Go语言设计模式的知识与应用。

全书共6章,分别为设计模式入门、创建型设计模式、结构型设计模式、行为型设计模式、设计模式扩展、设计模式与软件架构。

本书简洁而不失技术深度,内容覆盖Go语言的主流设计模式和软件架构,以极简的文字介绍了复杂的案例,是学习Go语言设计模式和软件架构的实用教程。

该书已经出版发行,并给大家申请到五折优惠,感兴趣的读者朋友欢迎通过如下方式购买。

代码语言:javascript
复制
FunTester原创专题推荐~FunTester宣言(ChatGPT版)2021年原创合集2022年原创合集接口功能测试专题性能测试专题Groovy专题Java、Groovy、Go、Python单测&白盒FunTester社群风采测试理论鸡汤FunTester视频专题案例分享:方案、BUG、爬虫UI自动化专题测试工具专题-- By FunTester
本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-03-23,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 FunTester 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 实战示例
    • 1)什么是工厂方法模式
      • 2)工厂方法模式的使用场景
        • 3)工厂方法模式的实现方式
          • 4)Go语言实战
            • 5)工厂方法模式的优缺点
            领券
            问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档