创立型模式提供了创建对象的机制,可能晋升已有代码的灵活性和可复用性。上面别离来说一下常见的几种创立性设计模式:
一、单例模式
定义:
一个类只容许创立一个对象(或者实例),那这个类就是一个单例类,这种设计模式就叫作单例模式。
应用场景:
从业务概念上,有些数据在零碎中只应该保留一份,就比拟适宜设计为单例类。比方,零碎的配置信息类。除此之外,咱们还能够应用单例解决资源拜访抵触的问题。
实现
概括起来,要实现一个单例,咱们须要关注的点无外乎上面几个:
- 构造函数须要是 private 拜访权限的,这样能力防止内部通过 new 创立实例;
- 思考对象创立时的线程平安问题;
- 思考是否反对提早加载;
- 思考 getInstance() 性能是否高(是否加锁)。
依据是否反对提早加载,单例模式分为饿汉式和懒汉式
1. 饿汉式
在类加载的时候,instance 动态实例就曾经创立并初始化好 了,所以,instance 实例的创立过程是线程平安的。
package singletontype Singleton struct{}var singleton *Singletonfunc init() { singleton = &Singleton{}}// GetInstance 获取实例func GetInstance() *Singleton { return singleton}
2. 懒汉式(双重检测)
懒汉式绝对于饿汉式的劣势是反对提早加载,然而因为须要加锁,有性能问题。
双重检测:在懒汉式的实现形式中,只有 instance 被创立之后,即使再调用 getInstance() 函数也不会再进入到加锁逻辑中,这样便既反对提早加载、又反对高并发了。
package singletonimport "sync"var ( lazySingleton *Singleton once = &sync.Once{})// GetLazyInstance 懒汉式func GetLazyInstance() *Singleton { if lazySingleton == nil { once.Do(func() { lazySingleton = &Singleton{} }) } return lazySingleton}
饿汉式将耗时的初始化操作,提前到程序启动的时候实现,这样就能防止在程序运行的时候,再去初始化导致的性能问题。
如果实例占用资源多,依照 fail-fast 的设计准则(有问题及早裸露),那咱们也心愿在程序启动时就将这个实例初始化好。如果资源不够,咱们能够立刻去修复。
综合来说,饿汉式还是比反对双重检测的懒汉式更举荐应用。
个别状况下,工厂模式分为三种更加细分的类型:简略工厂、工厂办法和形象工厂。在这三种细分的工厂模式中,简略工厂、工厂办法原理比较简单,在理论的我的项目中也比拟罕用。而形象工厂的原理略微简单点,在理论的我的项目中绝对也不罕用。
二、简略工厂(Simple Factory)
定义
定义一个工厂类,它能够依据参数的不同返回不同类的实例,被创立的实例通常都具备独特的父类。
应用场景
例如,一个物流公司,有陆运、海运和空运几种运输模式,这里的实现如下:申明一个Transport接口,它有一个叫deliver交付的办法,卡车Truck类和轮船Ship类都实现该接口,每个类都将以不同的形式实现该办法,卡车走陆路交付货物, 轮船走海路交付货物。工厂类能够依据传进的参数实例化相应的类,调用deliver办法都能实现运输的工作。
实现
package factorytype Transporter interface { Deliver()}type Truck struct {}func (J Truck) Deliver() { fmt.Println("this is Truck Deliver")}type Ship struct {}func (Y Ship) Deliver() { fmt.Println("this is Ship Deliver")}func NewTransport(t string) Transporter { switch t { case "truck": return Truck{} case "ship": return Ship{} } return nil}
只管简略工厂模式的代码实现中,有多处 if 分支判断逻辑,违反开闭准则,但衡量扩展性和可读性,这样的代码实现在大多数状况下(无需频繁的增加类,也没有太多的类)是没有问题的。
三、工厂办法(Factory Method)
定义:
简略工厂应用惟一的一个工厂管制着所有产品的实例化,而 工厂办法 中包含一个工厂接口,咱们能够动静的实现多种工厂,达到扩大的目标。
工厂办法模式比起简略工厂模式更加合乎开闭准则,当咱们新增一品种 的时候,只须要新增一个实现了接口的类即可。
应用场景:
当对象的创立逻辑比较复杂,不只是简略的 new 一下就能够,而是要组合其余类对象,做各种初始化操作的时候,咱们举荐应用工厂办法模式,将简单的创立逻辑拆分到多个工厂类中,让每个工厂类都不至于过于简单。
实现
还是下面的例子,如果公司开了分公司,在北京和广州都有了物流基地,运输路径的中央必定会不一样,又将如何实现呢?
package factory//工厂接口type CompanyInterface interface { Generate(t string) Transporter}//产品接口type Transporter interface { Deliver()}//具体工厂类type BjCompany struct {}type GZCompany struct {}// 工厂办法func (bj BjCompany) Generate(t string) Transporter { switch t { case "truck": return Truck{} case "ship": return Ship{} } return nil}func (gz GZCompany) Generate(t string) Transporter { switch t { case "truck": return Truck{} case "ship": return Ship{} } return nil}//具体产品及办法实现type BJTruck struct {}func (b BJTruck) Deliver() { fmt.Println("this is Truck Deliver")}type BJShip struct {}func (b BJShip) Deliver() { fmt.Println("this is Ship Deliver")}type GZTruck struct {}func (g GZTruck) Deliver() { fmt.Println("this is Truck Deliver")}type GZShip struct {}func (g GZShip) Deliver() { fmt.Println("this is Ship Deliver")}
简略工厂模式和工厂办法模式看起来很类似,本质区别就在于,如果在物流公司中间接创立运输产品,是依赖具体某个分公司的,扩展性、弹性、可维护性都较差,而如果将实例化的代码形象进去,不再依赖具体的公司,而是依赖于形象的公司接口,使对象的实现从应用中解耦,这样就领有很强的扩展性了,也能够称为 『依赖倒置准则』
四、形象工厂(Abstract Factory)
定义
形象工厂模式就是咱们的形象工厂约定了能够生产的产品,这些产品都蕴含多种规格,而后咱们能够从形象工厂为每一种规格派生出具体工厂类,而后让这些具体工厂类生产具体的产品。
咱们能够让一个工厂负责创立多个不同类型的对象,而不是只创立一种 对象。这样就能够无效地缩小工厂类的个数。
应用场景
默认的规定配置解析器类只会依据配置文件格式(Json、Xml、Yaml......)来分类,然而,如果类有两种分类方 式,比方,咱们既能够依照配置文件格式来分类,也能够依照解析的对象(Rule 规定配置还是 System 系统配置)来分类,那就会这有8 个 parser 类。
针对这种非凡的场景,如果还是持续用工厂办法来实现的话,咱们要针对每个 parser 都编写一个工厂类,也就是要编写 8 个工厂类。
形象工厂就是针对这种十分非凡的场景而诞生的。
package factory// IRuleConfigParser IRuleConfigParsertype IRuleConfigParser interface { Parse(data []byte)}// jsonRuleConfigParser jsonRuleConfigParsertype jsonRuleConfigParser struct{}// Parse Parsefunc (j jsonRuleConfigParser) Parse(data []byte) { panic("implement me")}// ISystemConfigParser ISystemConfigParsertype ISystemConfigParser interface { ParseSystem(data []byte)}// jsonSystemConfigParser jsonSystemConfigParsertype jsonSystemConfigParser struct{}// Parse Parsefunc (j jsonSystemConfigParser) ParseSystem(data []byte) { panic("implement me")}// IConfigParserFactory 工厂办法接口type IConfigParserFactory interface { CreateRuleParser() IRuleConfigParser CreateSystemParser() ISystemConfigParser}type jsonConfigParserFactory struct{}func (j jsonConfigParserFactory) CreateRuleParser() IRuleConfigParser { return jsonRuleConfigParser{}}func (j jsonConfigParserFactory) CreateSystemParser() ISystemConfigParser { return jsonSystemConfigParser{}}
五、建造者模式
定义:
建造者模式是用来创立一种类型的简单对象,通过设置不同的可选参数,“定制化”地创立不同的对象。
工厂模式是用来创立不同然而相干类型的对象(继承同一父类或者接口的一组子类),由给定的参数来决定创立哪种类型的对象。
应用场景:
- 参数很多
- 参数蕴含必选参数和可选参数
- 配置项之间有肯定的依赖关系
- 创立的对象是不可变对象
上述的状况间接应用构造函数设置必填项,通过 set() 办法设置可选配置项就无奈满足了
示例
顾客走进一家餐馆点餐,咱们利用工厂模式,依据用户不同的抉择,来制作不同的食物,比方披萨、汉堡、沙拉。
对于披萨来说,用户又有各种配料能够定制,比方奶酪、西红柿、起司,咱们通过建造者模式依据用户抉择的不同配料来制作披萨。
实现
咱们须要定义一个资源池配置类 ResourcePoolConfig。这里的资源池,你能够简略了解为线程池、连接池、对象池等。在这个资源池配置类中,有以下几个成员变量,也就是可配置项。
package builderimport "fmt"// ResourcePoolConfigOption optiontype ResourcePoolConfigOption struct { maxTotal int maxIdle int minIdle int}// ResourcePoolConfigOptFunc to set optiontype ResourcePoolConfigOptFunc func(option *ResourcePoolConfigOption)// NewResourcePoolConfig NewResourcePoolConfigfunc NewResourcePoolConfig(name string, opts ...ResourcePoolConfigOptFunc) (*ResourcePoolConfig, error) { if name == "" { return nil, fmt.Errorf("name can not be empty") } option := &ResourcePoolConfigOption{ maxTotal: 10, maxIdle: 9, minIdle: 1, } for _, opt := range opts { opt(option) } if option.maxTotal < 0 || option.maxIdle < 0 || option.minIdle < 0 { return nil, fmt.Errorf("args err, option: %v", option) } if option.maxTotal < option.maxIdle || option.minIdle > option.maxIdle { return nil, fmt.Errorf("args err, option: %v", option) } return &ResourcePoolConfig{ name: name, maxTotal: option.maxTotal, maxIdle: option.maxIdle, minIdle: option.minIdle, }, nil}
参考资料:
1、《设计模式之美》
2、https://refactoringguru.cn/de...
3、https://lailin.xyz/post/go-de...