Merge remote-tracking branch 'origin/master'

This commit is contained in:
Edward 2020-04-24 23:51:46 +08:00
commit 5a2722337a
16 changed files with 377 additions and 141 deletions

View File

@ -4,47 +4,54 @@
[![Build Status](https://travis-ci.org/senghoo/golang-design-pattern.svg?branch=master)](https://travis-ci.org/senghoo/golang-design-pattern)
## 姿势
以实际代码示例展示设计模式
+ 所谓模式就是套路,如功夫,招有定式
+ 这里就是以实际代码示例展示设计模式,通俗易懂
+ 除了常见的23种普适的设计模式,Go也有一些属于自己的模式
## 创建型模式
* [简单工厂模式Simple Factory](./creation/00_simple_factory)
* [工厂方法模式Factory Method](./creation/04_factory_method)
* [抽象工厂模式Abstract Factory](./creation/05_abstract_factory)
* [创建者模式Builder](./creation/06_builder)
* [原型模式Prototype](./creation/07_prototype)
* [单例模式Singleton](./creation/03_singleton)
+ [简单工厂模式Simple Factory](./creation/00_simple_factory)
+ [工厂方法模式Factory Method](./creation/04_factory_method)
+ [抽象工厂模式Abstract Factory](./creation/05_abstract_factory)
+ [创建者模式Builder](./creation/06_builder)
+ [原型模式Prototype](./creation/07_prototype)
+ [单例模式Singleton](./creation/03_singleton)
## 结构型模式
* [外观模式Facade](./01_facade)
* [适配器模式Adapter](./02_adapter)
* [代理模式Proxy](./09_proxy)
* [组合模式Composite](./13_composite)
* [享元模式Flyweight](./18_flyweight)
* [装饰模式Decorator](./20_decorator)
* [桥模式Bridge](./22_bridge)
+ [外观模式Facade](./01_facade)
+ [适配器模式Adapter](./02_adapter)
+ [代理模式Proxy](./09_proxy)
+ [组合模式Composite](./13_composite)
+ [享元模式Flyweight](./18_flyweight)
+ [装饰模式Decorator](./20_decorator)
+ [桥模式Bridge](./22_bridge)
## 行为型模式
* [中介者模式Mediator](./08_mediator)
* [观察者模式Observer](./10_observer)
* [命令模式Command](./11_command)
* [迭代器模式Iterator](./12_iterator)
* [模板方法模式Template Method](./14_template_method)
* [策略模式Strategy](./15_strategy)
* [状态模式State](./16_state)
* [备忘录模式Memento](./17_memento)
* [解释器模式Interpreter](./19_interpreter)
* [职责链模式Chain of Responsibility](./21_chain_of_responsibility)
* [访问者模式Visitor](./23_visitor)
+ [中介者模式Mediator](./08_mediator)
+ [观察者模式Observer](./10_observer)
+ [命令模式Command](./11_command)
+ [迭代器模式Iterator](./12_iterator)
+ [模板方法模式Template Method](./14_template_method)
+ [策略模式Strategy](./15_strategy)
+ [状态模式State](./16_state)
+ [备忘录模式Memento](./17_memento)
+ [解释器模式Interpreter](./19_interpreter)
+ [职责链模式Chain of Responsibility](./21_chain_of_responsibility)
+ [访问者模式Visitor](./23_visitor)
## Design patters Articles
[GO模式](https://github.com/tmrts/go-patterns)
[本设计模式的原始代码](https://github.com/senghoo/golang-design-pattern)
[参考代码1](https://github.com/tmrts/go-patterns)
[参考代码2](https://github.com/senghoo/golang-design-pattern)
## 更多
需要重新温习下Go基础?看这里
[go-exercise](https://github.com/crazybber/go-exercise)

View File

@ -1,3 +1,9 @@
# 单例模式
使用懒惰模式的单例模式,使用双重检查加锁保证线程安全
大名鼎鼎的单例模式,永远返回相同内存位置的绝对的、同一个实例对象。
Go有两种常见的单例模式
+ 使用懒惰模式的单例模式,使用`once.Do()`的双重同步检查保证线程安全生成单实例
+ 使用初始化的`init(){}`能力保证只生成一个实例

View File

@ -2,17 +2,50 @@ package singleton
import "sync"
//Singleton 是单例模式类
type Singleton struct{}
////////////////////////////////
//way 1
//使用 sync的 once.Do(){}确保执行一次
////////////////////////////////
var singleton *Singleton
//Worker Singleton 是单例模式类
type Worker struct{}
//better to be pointer
var onlyTheWorker *Worker
// init a control
var once sync.Once
//GetInstance 用于获取单例模式对象
func GetInstance() *Singleton {
//GetWorkerInstance 总是获取到同一个Worker对象(内存位置相同)
func GetWorkerInstance() *Worker {
//be sure ,to do this,only once!
once.Do(func() {
singleton = &Singleton{}
onlyTheWorker = &Worker{}
})
return singleton
return onlyTheWorker
}
//Manager Singleton 是单例模式类
type Manager struct{}
//better to be pointer
var instance *Manager
//better to be pointer
var onlyTheManager *Manager
////////////////////////////////
//way2
//使用func init(){}函数来初始化保证,只初始化一次,更简单.
////////////////////////////////
func init() {
onlyTheManager = &Manager{}
}
//GetManagerInstance 总是获取到同一个Manager对象(内存位置相同)
func GetManagerInstance() *Manager {
return onlyTheManager
}

View File

@ -5,30 +5,58 @@ import (
"testing"
)
const parCount = 100
const workerCount = 500
func TestSingleton(t *testing.T) {
ins1 := GetInstance()
ins2 := GetInstance()
func TestWorkerSingleton(t *testing.T) {
ins1 := GetWorkerInstance()
ins2 := GetWorkerInstance()
if ins1 != ins2 {
t.Fatal("instance is not equal")
t.Fatal("worker(instance) is not exactly the same")
}
}
func TestParallelSingleton(t *testing.T) {
// 获取500次Worker 是否总是同一个worker
func TestParallelWorkerSingleton(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(parCount)
instances := [parCount]*Singleton{}
for i := 0; i < parCount; i++ {
wg.Add(workerCount)
instances := [workerCount]*Worker{}
for i := 0; i < workerCount; i++ {
go func(index int) {
instances[index] = GetInstance()
instances[index] = GetWorkerInstance()
wg.Done()
}(i)
}
wg.Wait()
for i := 1; i < parCount; i++ {
for i := 1; i < workerCount; i++ {
if instances[i] != instances[i-1] {
t.Fatal("instance is not equal")
t.Fatal("Worker instance is not equal")
}
}
}
func TestManagerSingleton(t *testing.T) {
ins1 := GetManagerInstance()
ins2 := GetManagerInstance()
if ins1 != ins2 {
t.Fatal("Manager(instance) is not exactly the same")
}
}
// 获取500次Manager 是否总是同一个Manager
func TestParallelManagerSingleton(t *testing.T) {
wg := sync.WaitGroup{}
wg.Add(workerCount)
instances := [workerCount]*Manager{}
for i := 0; i < workerCount; i++ {
go func(index int) {
instances[index] = GetManagerInstance()
wg.Done()
}(i)
}
wg.Wait()
for i := 1; i < workerCount; i++ {
if instances[i] != instances[i-1] {
t.Fatal("Manager instance is not exactly equal")
}
}
}

View File

@ -2,4 +2,6 @@
工厂方法模式使用子类的方式延迟生成对象到子类中实现。
Go中不存在继承 所以使用匿名组合来实现
不同的工厂对象,返回一个实现了某接口的类型对象,不同的工厂返回不同实现了相同接口的不同对象,在只能使用特定的类简单工厂的基础上,使用的代码和类生成的灵活性大大增加。
Go中的继承关系是使用匿名组合来实现的。

View File

@ -1,66 +1,84 @@
package factorymethod
//Operator 是被封装的实际类接口
type Operator interface {
SetA(int)
SetB(int)
Result() int
import (
"fmt"
"strconv"
)
//Assistant 是robot能做的事情
type Assistant interface {
Clean(int)
Speak(string)
Work() string
}
//OperatorFactory 是工厂接口
type OperatorFactory interface {
Create() Operator
//IRobotFactory must be implemented by Factory
//different Factory create different robot
type IRobotFactory interface {
Build() Assistant
}
//OperatorBase 是Operator 接口实现的基类,封装公用方法
type OperatorBase struct {
a, b int
//BasicRobotModel 是基本的机器人模型
type BasicRobotModel struct {
words string
workTime int
}
//SetA 设置 A
func (o *OperatorBase) SetA(a int) {
o.a = a
//Clean 打扫
func (b *BasicRobotModel) Clean(a int) {
b.workTime = a
fmt.Printf("i can clean :%d hours\n", a)
}
//SetB 设置 B
func (o *OperatorBase) SetB(b int) {
o.b = b
//Speak 说话
func (b *BasicRobotModel) Speak(w string) {
b.words = w
fmt.Printf("my name is: %s\n", w)
}
//PlusOperatorFactory 是 PlusOperator 的工厂类
type PlusOperatorFactory struct{}
//Work main work
func (b *BasicRobotModel) Work() string {
return fmt.Sprint("my main work is do somthing")
}
func (PlusOperatorFactory) Create() Operator {
return &PlusOperator{
OperatorBase: &OperatorBase{},
//FightingRobotFactory 生产各类军工机器人
type FightingRobotFactory struct{}
//Build a robot from FightingRobotFactory
func (FightingRobotFactory) Build() Assistant {
return &FightingRobot{
BasicRobotModel: &BasicRobotModel{},
}
}
//PlusOperator Operator 的实际加法实现
type PlusOperator struct {
*OperatorBase
//FightingRobot 实际的战斗机器人
type FightingRobot struct {
*BasicRobotModel
}
//Result 获取结果
func (o PlusOperator) Result() int {
return o.a + o.b
//Work for FightingRobot to do some fighting
func (f FightingRobot) Work() string {
fmt.Printf("%s\n", "i can fighting")
return "i can fighting" + strconv.Itoa(f.workTime)
}
//MinusOperatorFactory 是 MinusOperator 的工厂类
type MinusOperatorFactory struct{}
//HomeRobotFactory 生产各类家用机器人
type HomeRobotFactory struct{}
func (MinusOperatorFactory) Create() Operator {
return &MinusOperator{
OperatorBase: &OperatorBase{},
//Build a robot from HomeRobotFactory
func (HomeRobotFactory) Build() Assistant {
return &HomeRobot{
BasicRobotModel: &BasicRobotModel{},
}
}
//MinusOperator Operator 的实际减法实现
type MinusOperator struct {
*OperatorBase
//HomeRobot 实际的家用机器人
type HomeRobot struct {
*BasicRobotModel
}
//Result 获取结果
func (o MinusOperator) Result() int {
return o.a - o.b
//Work robot do some work
func (h HomeRobot) Work() string {
fmt.Printf("%s\n", "i can do homework")
return "i can do homework" + strconv.Itoa(h.workTime)
}

View File

@ -2,25 +2,26 @@ package factorymethod
import "testing"
func compute(factory OperatorFactory, a, b int) int {
op := factory.Create()
op.SetA(a)
op.SetB(b)
return op.Result()
func doWork(factory IRobotFactory, cleanhour int) string {
robot := factory.Build()
robot.Clean(cleanhour)
robot.Speak("robot name")
return robot.Work()
}
func TestOperator(t *testing.T) {
var (
factory OperatorFactory
)
func TestRobotFactory(t *testing.T) {
var factory IRobotFactory
factory = PlusOperatorFactory{}
if compute(factory, 1, 2) != 3 {
factory = FightingRobotFactory{}
if doWork(factory, 2) != "i can fighting2" {
t.Fatal("error with factory method pattern")
}
factory = MinusOperatorFactory{}
if compute(factory, 4, 2) != 2 {
factory = HomeRobotFactory{}
if doWork(factory, 1) != "i can do homework1" {
t.Fatal("error with factory method pattern")
}
}

View File

@ -1,8 +1,12 @@
# 抽象工厂模式
抽象工厂模式用于生成产品族的工厂,所生成的对象是有关联的。
抽象工厂模式用于生成具有多产品种类生产能力的的工厂,所生成的对象往往是有关联的。
如果抽象工厂退化成生成的对象无关联则成为工厂函数模式。
如果抽象工厂退化成生成的对象无关联的或者单一的产品种类则成为工厂函数模式。
参考:[对比](https://blog.csdn.net/wyxhd2008/article/details/5597975)
![对比图片](../../images/abstract-factorys-method.png)
比如本例子中使用RDB和XML存储订单信息抽象工厂分别能生成相关的主订单信息和订单详情信息。
如果业务逻辑中需要替换使用的时候只需要改动工厂函数相关的类就能替换使用不同的存储方式了。

View File

@ -1,5 +1,5 @@
# 原型模式
原型模式使对象能复制自身,并且暴露到接口中,使客户端面向接口编程时,不知道接口实际对象的情况下生成新的对象。
原型模式用于快速复制具有相同属性的自身对象.
原型模式配合原型管理器使用,使得客户端在不知道具体类的情况下,通过接口管理器得到新的实例,并且包含部分预设定配置。
一般是通过实现实现: `Clone()`接口来实现,注意**必须返回新的内存实例**.

View File

@ -1,24 +1,26 @@
package prototype
//Cloneable 是原型对象需要实现的接口
//Cloneable is the key interface
type Cloneable interface {
Clone() Cloneable
}
type PrototypeManager struct {
prototypes map[string]Cloneable
//cloneLab 克隆实验室,可以克隆很多动物
type cloneLab struct {
animals map[string]Cloneable
}
func NewPrototypeManager() *PrototypeManager {
return &PrototypeManager{
prototypes: make(map[string]Cloneable),
//new 返回一个
func newCloneLab() *cloneLab {
return &cloneLab{
animals: make(map[string]Cloneable),
}
}
func (p *PrototypeManager) Get(name string) Cloneable {
return p.prototypes[name]
func (c *cloneLab) Get(name string) Cloneable {
return c.animals[name]
}
func (p *PrototypeManager) Set(name string, prototype Cloneable) {
p.prototypes[name] = prototype
func (c *cloneLab) Set(name string, newObject Cloneable) {
c.animals[name] = newObject
}

View File

@ -2,51 +2,57 @@ package prototype
import "testing"
var manager *PrototypeManager
//cloneLab 克隆实验室
var lab *cloneLab
type Type1 struct {
name string
type sheep struct {
name string
weight int
}
func (t *Type1) Clone() Cloneable {
tc := *t
func (s *sheep) Clone() Cloneable {
tc := *s
return &tc
}
type Type2 struct {
name string
type cow struct {
name string
gender bool
}
func (t *Type2) Clone() Cloneable {
tc := *t
return &tc
func (c *cow) Clone() Cloneable {
newCow := &cow{
gender: c.gender,
name: c.name,
}
return newCow
}
func TestClone(t *testing.T) {
t1 := manager.Get("t1")
t2 := t1.Clone()
sheep1 := &sheep{
name: "sheep",
weight: 10,
}
if t1 == t2 {
sheep2 := sheep1.Clone()
if sheep1 == sheep2 {
t.Fatal("error! get clone not working")
}
}
func TestCloneFromManager(t *testing.T) {
c := manager.Get("t1").Clone()
func TestCloneFromLab(t *testing.T) {
t1 := c.(*Type1)
if t1.name != "type1" {
lab := newCloneLab()
lab.Set("cow", &cow{name: "i am cow", gender: true})
c := lab.Get("cow").Clone()
cw := c.(*cow)
if cw.name != "i am cow" {
t.Fatal("error")
}
}
func init() {
manager = NewPrototypeManager()
t1 := &Type1{
name: "type1",
}
manager.Set("t1", t1)
}

View File

@ -0,0 +1,3 @@
# Object Pool
对象池创建模式,根据业务和执行的需要,用于一次性准备大量的预置对象

View File

@ -0,0 +1,23 @@
package objectpool
type doctor struct {
name string
kind int //科室
}
type pool chan *doctor
func newPool(total int) pool {
p := make(pool, total)
for i := 0; i < total; i++ {
p <- new(doctor)
}
return p
}
//surgery
func (d doctor) surgery() {
}

View File

@ -0,0 +1,20 @@
package objectpool
import (
"testing"
)
func TestObjectPool(t *testing.T) {
p := newPool(2)
select {
case obj := <-p:
obj.surgery( /*...*/ )
p <- obj
default:
// No more objects left — retry later or fail
return
}
}

View File

@ -0,0 +1,83 @@
package idiom
import (
"os"
"testing"
)
func TestFileFunctionOptions(t *testing.T) {
err := New("empty.txt")
if err != nil {
panic(err)
}
os.Remove("empty.txt")
err = New("file.txt", UID(1000), Contents("input some data"))
if err != nil {
panic(err)
}
os.Remove("file.txt")
}
///Options is key struct
type Options struct {
UID int
GID int
Flags int
Contents string
Permissions os.FileMode
}
//Option func is key func
type Option func(*Options)
func UID(userID int) Option {
return func(args *Options) {
args.UID = userID
}
}
func GID(groupID int) Option {
return func(args *Options) {
args.GID = groupID
}
}
func Contents(c string) Option {
return func(args *Options) {
args.Contents = c
}
}
func Permissions(perms os.FileMode) Option {
return func(args *Options) {
args.Permissions = perms
}
}
func New(filepath string, setters ...Option) error {
// Default Options
args := &Options{
UID: os.Getuid(),
GID: os.Getgid(),
Contents: "",
Permissions: 0666,
Flags: os.O_CREATE | os.O_EXCL | os.O_WRONLY,
}
for _, setter := range setters {
setter(args)
}
f, err := os.OpenFile(filepath, args.Flags, args.Permissions)
if err != nil {
return err
}
defer f.Close()
if _, err := f.WriteString(args.Contents); err != nil {
return err
}
return err
}

Binary file not shown.

After

Width:  |  Height:  |  Size: 67 KiB