设计模式六大原则
1.开闭原则:
开闭原则是指对扩展开放,对修改关闭.在程序需要进行拓展时,不能修改所有的代码,实现一个热插拔的效果.从而使程序扩展性更好,易于维护和升级.
2.里氏代换原则:
任何基类可以出现的地方,子类一定可以出现,是继承复用的基石.只有当子类可以替换基类且软件的组件功能不受影响.基类才能真正被复用.使子类能够在基类的基础上增加新的行为.是对开闭原则的补充.开闭原则的步骤是抽象化,而基类和子类的继承关系是抽象化的具体实现.
3.依赖倒转原则:
是开闭原则的基础.具体内容是针对接口编程.依赖于抽象,而不依赖于实体.
4.接口隔离原则:
是指使用多个隔离接口比使用单个接口隔离更好.还有另一个意义是降低类之间的耦合度.
5.迪米特法则:
又称为最少知道原则,是指一个实体应当尽量少的与其他实体之间发生相互作用,使系统功能模块相对独立.
6.合成复用原则:
指通过关联关系(包括组合关系和聚合关系)在一个新对象中使用一些已有的对象,使它们成为新对象的一部分.新对象通过委托已有对象的方法实现复制.
7.单例模式:
单例模式的类提供了一种访问其唯一对象的方法,该对象可以直接被访问,无须实例化.单例模式保证了一个类的对象只存在一个.同时维护了一个对象的全局访问点.
7.1使用场景:
如果程序中的某个类对于所有客户端都只有一个可用实例.
想要严格控制全局变量.
开发网站的计数器.
开发程序的日志记录.共享的日志文件一直处于打开状态.所以只能有一个实例进行操作.
web应用程序读取配置文件,因为配置文件是共享资源.
设计数据库连建池.
设计线程池.
7.2单例实现:
7.2.1懒汉式单例模式:
在创建对象时不直接创建对象,在加载配置文件时才创建对象.
// 单例类.
type singleton struct {
Value int
}
// 私有变量.
var instance *singleton
// 获取单例对象.
func getInstanceSingleton() *singleton {
if instance == nil {
instance := new(singleton)
}
return instance
}
在并发条件下,协程并不安全可能会创建多个对象.
7.2.2Sync.Mutex懒汉式:
import "sync"
// 单例类.
type singleton struct {
Value int
}
// 私有变量.
var instance *singleton
// 锁对象.
var mutex sync.Mutex
// 获取单例对象.
func getInstanceSingleton() *singleton {
mutex.Lock()
defer mutex.Unlock()
if instance == nil {
instance := new(singleton)
}
return instance
}
保证了协程并发安全,但是每次都要加锁解锁,性能上不够高效.
7.2.3饿汉式单例模式:
在创建对象时,不判断创建的对象是否为空,直接创建对象.饿汉单例是并发安全的.唯一的缺点是导入包的时候会创建对象.并且创建的对象会持续存储在内存中.
import "fmt"
type singleton2 struct {
}
var instance2 *singleton2
func init() {
if instance2 == nil {
instance2 = new(singleton2)
fmt.Println("创建了单个实例")
}
}
// 提供实例函数.
func getInstance() *singleton2 {
return instance2
}
7.2.4双重检查单例模式:
import "sync"
// 单例类.
type singleton struct {
Value int
}
// 私有变量.
var instance *singleton
// 锁对象.
var mutex sync.Mutex
// 获取单例对象.对象为空时,进行加锁.在获取对象就不需要加速了.
func getInstanceSingleton() *singleton {
if instance == nil {
mutex.Lock()
instance := new(singleton)
mutex.Unlock()
}
return instance
}
7.2.5sync.Once单例模式:
是Go标准库提供的函数,只执行一次实现.通常用于单例模式,如初始化配置 保持数据库连接等.作用和init函数类似.但有区别.init函数会在其所在的包首次被加载时执行,如果被加载的包不立即被使用,既浪费了内存空间又延长了加载时间.
sync.Once可以在代码的任意位置被初始化和调用,在并发场景中是并发安全的.
import (
"fmt"
"sync"
)
var one sync.Once
var instance3 *singleton3
type singleton3 struct {
}
func getSingleton3() *singleton3 {
one.Do(func() {
instance3 = new(singleton3)
fmt.Println("创建单个实例")
})
return instance3
}
7.3实践:
import (
"fmt"
_ "gomodule/pubsub"
"sync"
)
var lock = &sync.Mutex{}
type singletonTest struct {
}
var instance *singletonTest
// 获取实例.
func getSingletonTest() *singletonTest {
if instance == nil {
lock.Lock()
defer lock.Unlock()
if instance == nil {
fmt.Println("创建单个实例")
instance = new(singletonTest)
} else {
fmt.Println("已创建单个实例")
}
} else {
fmt.Println("已创建单个实例")
}
return instance
}
func main() {
for i := 0; i < 10; i++ {
go getSingletonTest()
}
fmt.Scanln()
}
*** 执行结果:***
7.4单例模式优点:
单例模式可以扩展为工厂模式.
由于在系统内存中只有一个对象,因此需要频繁创建和销毁对象的系统,可以提高性能.
7.5单例模式缺点:
单例模式不是抽象的,可扩展性低.
滥用单例模式会产生一些负面问题.为了节省资源,如果使用单例模式设计数据库对象,可能会导致共享连接池对象没有被释放.
知行合一,心外物.
如果大家喜欢我的分享的话,可以关注我的微信公众号
念何架构之路