快速理解
工厂模式本质上就是创建了一个接口,来去创建具体的产品!!!
就像是下面的样子,这就是最简单的工厂模式
func NewRequest(requestType string) Request {
switch requestType {
case RequestTypeHTTP:
return HTTP{}
case RequestTypeBrowser:
return Browser{}
default:
return HTTP{}
}
}
而针对于不同的场景又细分出了简单工厂模式,工厂方法模式,抽象工厂模式。但是,他们本质上还是上面的这个创建器。(我觉得go里面分成简单工厂跟抽象工厂就行)
这里补充几个概念:
- 工厂:就是我们上面的创建器
- 产品:我们最终提供给上层的结构体、函数、接口等
- 抽象:就是给产品套层皮,大家用的是这层皮,不是用的具体产品,这层皮再去用具体的产品。(这就是一个解耦的关键点,只要抽象层不变,上层代码均不变)
模式 | 创建对象 | |
---|---|---|
简单工厂模式 | 具体产品 | |
抽象工厂模式 | 工厂 | 工厂创建工厂,然后工厂创建产品 |
这里一个容易误解的点是,抽象工厂不是创建抽象层的,而是创建工厂的超级工厂。
抽象层:抽象产品,抽象方法,抽象的工厂
抽象层都是可以由工厂创建的
适用场景
- 需要创建的对象属于多个产品族,而系统只消费其中某一产品族的对象。例如,有两个产品族:Windows组件和Mac组件,系统只会消费其中一族的组件对象。
- 系统需要在多个产品族之间进行切换,例如允许在Mac风格的组件和Windows风格的组件之间切换。
- 需要 independency(独立性),可以通过 abstract layer(抽象层)将具体实现和使用者分离。(这个其实是优点的一部分)
- 当一个系统不应当依赖于产品类实例如何被创建、组合和表达的时候。这对于构建可定制化和可配置化的系统非常有用。(即创建可以被封装,上层不需要传参的时候)
- 系统中有多于一个的产品族,而且很明显的是定义它们的接口是一样的。
- 需要提供一个产品类库,而且只想显示它们的接口而不是实现。(本质上是返回了一套方法)
- 需要能够替换整个产品族而不是单一的产品实例,例如能切换不同供应商的产品。(比如从 Windows 换到 Linux 这样,两者的实现不同,但是两者都是操作系统)
初始化复杂的结构体,我们可以把初始化全部封装,暴露一个 interface 给上层调用 (这样可以依赖抽象,而不是依赖具体)
使得我们最终修改底层代码时,只要函数参数及返回值不变,上层代码基本不需要修改。
简单实践
简单工厂模式
这里是采用常量来区分各种创建对象,当然也可以一种一个函数(个人觉得不够优雅)
package fetchers
import (
"errors"
"fmt"
"github.com/playwright-community/playwright-go"
"io"
"net/http"
"net/url"
"serivces"
"strconv"
"time"
)
const (
RequestTypeHTTP = "http"
RequestTypeBrowser = "browser"
)
type Request interface {
Get(u string, proxy services.Proxy, timeout int64) (content string, err error)
}
// NewRequest returns a new Request according to the name
// 简单工厂模式
func NewRequest(requestType string) Request {
switch requestType {
case RequestTypeHTTP:
return HTTP{}
case RequestTypeBrowser:
return Browser{}
default:
return HTTP{}
}
}
type HTTP struct {
}
type Browser struct {
}
func (Browser) Get(u string, proxy services.Proxy, timeout int64) (string, error) {
//...
}
func (HTTP) Get(u string, proxy services.Proxy, timeout int64) (string, error) {
//...
}