mirror of
https://github.com/crazybber/go-pattern-examples.git
synced 2024-11-25 13:16:02 +03:00
Merge remote-tracking branch 'origin/master'
This commit is contained in:
commit
5a2722337a
63
README.md
63
README.md
@ -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)
|
||||
|
@ -1,3 +1,9 @@
|
||||
# 单例模式
|
||||
|
||||
使用懒惰模式的单例模式,使用双重检查加锁保证线程安全
|
||||
大名鼎鼎的单例模式,永远返回相同内存位置的绝对的、同一个实例对象。
|
||||
|
||||
Go有两种常见的单例模式:
|
||||
|
||||
+ 使用懒惰模式的单例模式,使用`once.Do()`的双重同步检查保证线程安全生成单实例
|
||||
|
||||
+ 使用初始化的`init(){}`能力保证只生成一个实例
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -2,4 +2,6 @@
|
||||
|
||||
工厂方法模式使用子类的方式延迟生成对象到子类中实现。
|
||||
|
||||
Go中不存在继承 所以使用匿名组合来实现
|
||||
不同的工厂对象,返回一个实现了某接口的类型对象,不同的工厂返回不同实现了相同接口的不同对象,在只能使用特定的类简单工厂的基础上,使用的代码和类生成的灵活性大大增加。
|
||||
|
||||
Go中的继承关系是使用匿名组合来实现的。
|
||||
|
@ -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)
|
||||
}
|
||||
|
@ -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")
|
||||
}
|
||||
}
|
||||
|
@ -1,8 +1,12 @@
|
||||
# 抽象工厂模式
|
||||
|
||||
抽象工厂模式用于生成产品族的工厂,所生成的对象是有关联的。
|
||||
抽象工厂模式用于生成具有多产品种类生产能力的的工厂,所生成的对象往往是有关联的。
|
||||
|
||||
如果抽象工厂退化成生成的对象无关联则成为工厂函数模式。
|
||||
如果抽象工厂退化成生成的对象无关联的或者单一的产品种类则成为工厂函数模式。
|
||||
|
||||
参考:[对比](https://blog.csdn.net/wyxhd2008/article/details/5597975)
|
||||
|
||||
![对比图片](../../images/abstract-factorys-method.png)
|
||||
|
||||
比如本例子中使用RDB和XML存储订单信息,抽象工厂分别能生成相关的主订单信息和订单详情信息。
|
||||
如果业务逻辑中需要替换使用的时候只需要改动工厂函数相关的类就能替换使用不同的存储方式了。
|
||||
|
@ -1,5 +1,5 @@
|
||||
# 原型模式
|
||||
|
||||
原型模式使对象能复制自身,并且暴露到接口中,使客户端面向接口编程时,不知道接口实际对象的情况下生成新的对象。
|
||||
原型模式用于快速复制具有相同属性的自身对象.
|
||||
|
||||
原型模式配合原型管理器使用,使得客户端在不知道具体类的情况下,通过接口管理器得到新的实例,并且包含部分预设定配置。
|
||||
一般是通过实现实现: `Clone()`接口来实现,注意**必须返回新的内存实例**.
|
||||
|
@ -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
|
||||
}
|
||||
|
@ -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)
|
||||
}
|
||||
|
3
creation/24_object_pool/README.md
Normal file
3
creation/24_object_pool/README.md
Normal file
@ -0,0 +1,3 @@
|
||||
# Object Pool
|
||||
|
||||
对象池创建模式,根据业务和执行的需要,用于一次性准备大量的预置对象
|
23
creation/24_object_pool/obejct_poo.go
Normal file
23
creation/24_object_pool/obejct_poo.go
Normal 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() {
|
||||
|
||||
}
|
20
creation/24_object_pool/object_pool_test.go
Normal file
20
creation/24_object_pool/object_pool_test.go
Normal 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
|
||||
}
|
||||
}
|
83
idiom/functional_options_test.go
Normal file
83
idiom/functional_options_test.go
Normal 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
|
||||
}
|
BIN
images/abstract-factorys-method.png
Normal file
BIN
images/abstract-factorys-method.png
Normal file
Binary file not shown.
After Width: | Height: | Size: 67 KiB |
Loading…
Reference in New Issue
Block a user