导语| 继上篇【快珍藏!最全GO语言实现设计模式】,本文持续列出GO语言实现的经典设计模式示例,每个示例都精心设计,力求合乎模式构造,可作为日常编码参考,同时一些罕用的设计模式融入了开发实际经验总结,帮忙大家在平时工作中灵活运用。
解释器模式
(一)概念
解释器模式用于形容如何应用面向对象语言形成一个简略的语言解释器。在某些状况下,为了更好地形容某一些特定类型的问题,咱们能够创立一种新的语言,这种语言领有本人的表达式和构造,即文法规定,这些问题的实例将对应为该语言中的句子。此时,能够应用解释器模式来设计这种新的语言。对解释器模式的学习可能加深咱们对面向对象思维的了解,并且把握编程语言中文法规则的解释过程。
(二)示例
定义一个解析特征值的语句解释器,提供是否蕴含特征值的终结表达式,并提供或表达式与且表达式,同时,生成南极洲特色判断表达式,及美国人特色判断表达式,最初测试程序依据对象特征值形容,通过表达式判断是否为真。
特征值解释器
package interpreterimport "strings"// Expression 表达式接口,蕴含一个解释办法type Expression interface { Interpret(context string) bool}// terminalExpression 终结符表达式,判断表达式中是否蕴含匹配数据type terminalExpression struct { matchData string}func NewTerminalExpression(matchData string) *terminalExpression { return &terminalExpression{matchData: matchData}}// Interpret 判断是否蕴含匹配字符func (t *terminalExpression) Interpret(context string) bool { if strings.Contains(context, t.matchData) { return true } return false}// orExpression 或表达式type orExpression struct { left, right Expression}func NewOrExpression(left, right Expression) *orExpression { return &orExpression{ left: left, right: right, }}func (o *orExpression) Interpret(context string) bool { return o.left.Interpret(context) || o.right.Interpret(context)}// andExpression 与表达式type andExpression struct { left, right Expression}func NewAndExpression(left, right Expression) *andExpression { return &andExpression{ left: left, right: right, }}func (o *andExpression) Interpret(context string) bool { return o.left.Interpret(context) && o.right.Interpret(context)}
测试程序
package interpreterimport ( "fmt" "testing")func TestInterpreter(t *testing.T) { isAntarcticaExpression := generateCheckAntarcticaExpression() // 大洲形容1 continentDescription1 := "此大洲生存着大量企鹅,全年高温,并且随同着有暴风雪" fmt.Printf("%s,是否是南极洲?%t\n", continentDescription1, isAntarcticaExpression.Interpret(continentDescription1)) // 大洲形容2 continentDescription2 := "此大洲生存着狮子,全年高温多雨" fmt.Printf("%s,是否是南极洲?%t\n", continentDescription2, isAntarcticaExpression.Interpret(continentDescription2)) isAmericanExpression := generateCheckAmericanExpression() peopleDescription1 := "此人生存在北美洲的黑人,说着英语,持有美国绿卡" fmt.Printf("%s,是否是美国人?%t\n", peopleDescription1, isAmericanExpression.Interpret(peopleDescription1)) peopleDescription2 := "此人生存在欧洲,说着英语,是欧洲议会议员" fmt.Printf("%s,是否是南极洲?%t\n", peopleDescription2, isAmericanExpression.Interpret(peopleDescription2))}// generateCheckAntarcticaExpression 生成校验是否是南极洲表达式func generateCheckAntarcticaExpression() Expression { // 判断南极洲的动物,或关系 animalExpression := NewOrExpression(NewTerminalExpression("企鹅"), NewTerminalExpression("蓝鲸")) // 判断南极洲的天气,与关系 weatherExpression := NewAndExpression(NewTerminalExpression("高温"), NewTerminalExpression("暴风雪")) // 最终返回动物与天气的与关系 return NewAndExpression(animalExpression, weatherExpression)}// generateCheckAmericanExpression 生成查看美国人表达式func generateCheckAmericanExpression() Expression { // 人种判断,或关系 raceExpression := NewOrExpression(NewTerminalExpression("白人"), NewTerminalExpression("黑人")) // 生存形式,与关系 lifeStyleExpression := NewAndExpression(NewTerminalExpression("英语"), NewTerminalExpression("北美洲")) // 身份,与关系 identityExpression := NewAndExpression(lifeStyleExpression, NewTerminalExpression("美国绿卡")) return NewAndExpression(raceExpression, identityExpression)}
运行后果
=== RUN TestInterpreter此大洲生存着大量企鹅,全年高温,并且随同着有暴风雪,是否是南极洲?true此大洲生存着狮子,全年高温多雨,是否是南极洲?false此人生存在北美洲的黑人,说着英语,持有美国绿卡,是否是美国人?true此人生存在欧洲,说着英语,是欧洲议会议员,是否是美国人?false--- PASS: TestInterpreter (0.00s)PASS
适配器模式
(一)概念
适配器模式是一种结构型设计模式,它能使接口不兼容的对象可能相互合作。
适配器可负责两个对象间的封装器,它会接管对于一个对象的调用, 并将其转换为另一个对象可辨认的格局和接口。
(二)示例
通过充电宝给不同充电接口的手机充电是一个十分合乎适配器模式特色的生存示例;个别充电宝提供USB电源输入接口,手机充电输出接口则分为两类一是苹果手机的lightning接口,另一类是安卓手机的typeC接口,这两类接口都须要通过适配电源线连贯充电宝的USB接口,这里USB接口就相当于充电宝的通用接口,lightning或typeC接口要想充电须要通过充电线适配。
手机充电插头
package adapterimport "fmt"// HuaweiPlug 华为手机充电插槽接口type HuaweiPlug interface { ConnectTypeC() string}// HuaweiPhone 华为系列手机type HuaweiPhone struct { model string}// NewHuaweiPhone 华为手机创立办法func NewHuaweiPhone(model string) *HuaweiPhone { return &HuaweiPhone{ model: model, }}// ConnectTypeC 华为手机TypeC充电插槽func (h *HuaweiPhone) ConnectTypeC() string { return fmt.Sprintf("%v connect typeC plug", h.model)}// ApplePlug 苹果手机充电插槽type ApplePlug interface { ConnectLightning() string}// IPhone 苹果系列手机type IPhone struct { model string}// NewIPhone 苹果手机创立办法func NewIPhone(model string) *IPhone { return &IPhone{ model: model, }}// ConnectLightning 苹果手机Lightning充电插槽func (i *IPhone) ConnectLightning() string { return fmt.Sprintf("%v connect lightning plug", i.model)}
充电宝适配器
package adapterimport "fmt"// CommonPlug 通用的USB电源插槽type CommonPlug interface { ConnectUSB() string}// HuaweiPhonePlugAdapter 华为TypeC充电插槽适配通用USB充电插槽type HuaweiPhonePlugAdapter struct { huaweiPhone HuaweiPlug}// NewHuaweiPhonePlugAdapter 创立华为手机适配USB充电插槽适配器func NewHuaweiPhonePlugAdapter(huaweiPhone HuaweiPlug) *HuaweiPhonePlugAdapter { return &HuaweiPhonePlugAdapter{ huaweiPhone: huaweiPhone, }}// ConnectUSB 链接USBfunc (h *HuaweiPhonePlugAdapter) ConnectUSB() string { return fmt.Sprintf("%v adapt to usb ", h.huaweiPhone.ConnectTypeC())}// ApplePhonePlugAdapter 苹果Lightning充电插槽适配通用USB充电插槽type ApplePhonePlugAdapter struct { iPhone ApplePlug}// NewApplePhonePlugAdapter 创立苹果手机适配USB充电插槽适配器func NewApplePhonePlugAdapter(iPhone ApplePlug) *ApplePhonePlugAdapter { return &ApplePhonePlugAdapter{ iPhone: iPhone, }}// ConnectUSB 链接USBfunc (a *ApplePhonePlugAdapter) ConnectUSB() string { return fmt.Sprintf("%v adapt to usb ", a.iPhone.ConnectLightning())}// PowerBank 充电宝type PowerBank struct { brand string}// Charge 反对通用USB接口充电func (p *PowerBank) Charge(plug CommonPlug) string { return fmt.Sprintf("%v power bank connect usb plug, start charge for %v", p.brand, plug.ConnectUSB())}
测试程序
package adapterimport ( "fmt" "testing")func TestAdapter (t *testing.T) { huaweiMate40Pro := NewHuaweiPhone("华为 mate40 pro") iphone13MaxPro := NewIPhone("苹果 iphone13 pro max") powerBank := &PowerBank{"飞利浦"} fmt.Println(powerBank.Charge(NewHuaweiPhonePlugAdapter(huaweiMate40Pro))) fmt.Println(powerBank.Charge(NewApplePhonePlugAdapter(iphone13MaxPro)))}
- 运行后果
=== RUN TestAdapter飞利浦 power bank connect usb plug, start charge for 华为 mate40 pro connect typeC plug adapt to usb 飞利浦 power bank connect usb plug, start charge for 苹果 iphone13 pro max connect lightning plug adapt to usb --- PASS: TestAdapter (0.00s)PASS
桥接模式
(一)概念
桥接是一种结构型设计模式,可将业务逻辑或一个大类拆分为不同的层次结构, 从而能独立地进行开发。
层次结构中的第一层(通常称为形象局部)将蕴含对第二层 (实现局部) 对象的援用。形象局部将能将一些(有时是绝大部分)对本人的调用委派给实现局部的对象。所有的实现局部都有一个通用接口,因而它们能在形象局部外部互相替换。
简略的说,一个事物存在多个维度的变动点,每一个维度都形象出一个接口,事物援用这些接口实现整体行为逻辑,而每一个接口都能够存在多个变动的实现。
更简略的一句话:依赖接口编程。
(二)示例
对于一段经验的形容,经验就可能有多种实现,比方游览经验,探险经验这相当于第一档次的类构造,同时形容游览经验或探险经验又蕴含多个维度,比方如何达到目的地,在目的地发展了什么流动等,达到目的地有很多种形式,比方飞机、火车、汽车等;发展的流动又根据地点不同而不同,海边能够冲浪,山地能够攀岩,荒漠能够徒步穿梭等;这两个维度的变动点对于形容经验来说相当于第二档次类实现,通过接口被第一档次援用。
这里对于经验形容存在三个维度的变动,
1.经验自身的两个实现:游览经验与探险经验。
2.交通形式的两个实现:飞机和汽车。
3.发展流动的三个实现:冲浪、攀岩与徒步穿梭。
如果用一个类档次去实现就须要2*2*3=12个不同的实现类,如果用桥接模式仅须要2+2+3=7个不同的类,而且两种形式的加速度也不一样,比方减少一个交通形式火车,非桥接模式须要减少2*3*3-12=6个实现类,桥接模式2+3+3-7=1个实现类;桥接模式大大增加了类之间组合的灵活性。
交通工具
package bridge// Traffic 交通工具type Traffic interface { Transport() string}// airplane 飞机type airplane struct{}// Transport 坐飞机func (a *airplane) Transport() string { return "by airplane"}// car 汽车type car struct{}// Transport 坐汽车func (t *car) Transport() string { return "by car"}
目的地
package bridgeimport "fmt"// Location 地点type Location interface { Name() string // 地点名称 PlaySports() string // 参加静止}// namedLocation 被命名的地点,对立援用此类型,申明名字字段及获取办法type namedLocation struct { name string}// Name 获取地点名称func (n namedLocation) Name() string { return n.name}// seaside 海边type seaside struct { namedLocation}// NewSeaside 创立指定名字的海边,比方三亚湾func NewSeaside(name string) *seaside { return &seaside{ namedLocation: namedLocation{ name: name, }, }}// PlaySports 海边能够冲浪func (s *seaside) PlaySports() string { return fmt.Sprintf("surfing")}// mountain 山type mountain struct { namedLocation}// NewMountain 创立指定名字的山,比方泰山func NewMountain(name string) *mountain { return &mountain{ namedLocation: namedLocation{ name: name, }, }}// PlaySports 能够爬山func (m *mountain) PlaySports() string { return fmt.Sprintf("climbing")}// desert 荒漠type desert struct { namedLocation}// NewDesert 创立指定名字的荒漠,比方罗布泊func NewDesert(name string) *desert { return &desert{ namedLocation: namedLocation{ name: name, }, }}// PlaySports 荒漠能够徒步穿梭func (d *desert) PlaySports() string { return fmt.Sprintf("trekking")}
经验形容
package bridgeimport "fmt"// Experience 经验type Experience interface { Describe() string // 形容经验}// travelExperience 游览经验type travelExperience struct { subject string traffic Traffic location Location}// NewTravelExperience 创立游览经验,包含主题、交通形式、地点func NewTravelExperience(subject string, traffic Traffic, location Location) *travelExperience { return &travelExperience{ subject: subject, traffic: traffic, location: location, }}// Describe 形容游览经验func (t *travelExperience) Describe() string { return fmt.Sprintf("%s is to %s %s and %s", t.subject, t.location.Name(), t.traffic.Transport(), t.location.PlaySports())}// adventureExperience 探险经验type adventureExperience struct { survivalTraining string travelExperience}// NewAdventureExperience 创立探险经验,包含探险须要的培训,其余的与路由参数相似func NewAdventureExperience(training string, subject string, traffic Traffic, location Location) *adventureExperience { return &adventureExperience{ survivalTraining: training, travelExperience: *NewTravelExperience(subject, traffic, location), }}// Describe 形容探险经验func (a *adventureExperience) Describe() string { return fmt.Sprintf("after %s, %s", a.survivalTraining, a.travelExperience.Describe())}
测试程序
package bridgeimport ( "fmt" "testing")func TestBridge(t *testing.T) { // 坐飞机去三亚度蜜月 honeymoonTravel := NewTravelExperience("honeymoon", new(airplane), NewSeaside("SanyaYalongBay")) fmt.Println(honeymoonTravel.Describe()) // 坐车去泰山毕业游览 graduationTrip := NewTravelExperience("graduationTrip", new(car), NewMountain("Tarzan")) fmt.Println(graduationTrip.Describe()) // 野外生存培训后,坐车去罗布泊,徒步穿梭 desertAdventure := NewAdventureExperience("wilderness survival training", "adventure", new(car), NewDesert("Lop Nor")) fmt.Println(desertAdventure.Describe())}
运行后果
=== RUN TestBridgehoneymoon is to SanyaYalongBay by airplane and surfinggraduationTrip is to Tarzan by car and climbingafter wilderness survival training, adventure is to Lop Nor by car and trekking--- PASS: TestBridge (0.00s)PASS
组合模式
(一)概念
组合是一种结构型设计模式,你能够应用它将对象组合成树状构造,并且能像应用独立对象一样应用它们。
对于绝大多数须要生成树状构造的问题来说,组合都是十分受欢迎的解决方案。组合最次要的性能是在整个树状构造上递归调用办法并对后果进行汇总。
(二)示例
一般来说一个地区统计人口或经济总量,总是通过行政区划一层层上报汇总得出后果,区镇是最低一级行政区划,须要落实统计人口及经济总量的工作,再上一级行政区划须要将所辖区镇的数据汇总统计,以此类推每一级行政区划都须要统计人口与经济总量,就像一个倒过去的树状构造,各级行政区划对立的组件接口是统计人口与经济总量,区镇相当于最底层的叶子节点,两头级别行政区划相当于组合节点;上面代码以苏州市为例;
组件接口
package composite// Region 行政区,作为组合模式component接口type Region interface { Name() string // 名称 Population() int //人口 GDP() float64 // gdp}
区镇实现
package composite// town 区镇,组合模式中相当于叶子节点type town struct { name string population int gdp float64}// NewTown 创立区镇,依据名称、人口、GDPfunc NewTown(name string, population int, gdp float64) *town { return &town{ name: name, population: population, gdp: gdp, }}func (c *town) Name() string { return c.name}func (c *town) Population() int { return c.population}func (c *town) GDP() float64 { return c.gdp}
县市地市实现
package composite// cities 市,包含县市或者地市,组合模式中相当于compositetype cities struct { name string regions map[string]Region}// NewCities 创立一个市func NewCities(name string) *cities { return &cities{ name: name, regions: make(map[string]Region), }}func (c *cities) Name() string { return c.name}func (c *cities) Population() int { sum := 0 for _, r := range c.regions { sum += r.Population() } return sum}func (c *cities) GDP() float64 { sum := 0.0 for _, r := range c.regions { sum += r.GDP() } return sum}// Add 增加多个行政区func (c *cities) Add(regions ...Region) { for _, r := range regions { c.regions[r.Name()] = r }}// Remove 递归删除行政区func (c *cities) Remove(name string) { for n, r := range c.regions { if n == name { delete(c.regions, name) return } if city, ok := r.(*cities); ok { city.Remove(name) } }}func (c *cities) Regions() map[string]Region { return c.regions}
测试程序
package compositeimport ( "fmt" "testing")func TestComposite(t *testing.T) { gusu := NewTown("姑苏区", 100, 2000.00) fmt.Println(ShowRegionInfo(gusu)) wuzhong := NewTown("吴中区", 150, 2600.00) fmt.Println(ShowRegionInfo(wuzhong)) huqiu := NewTown("虎丘区", 80, 1800.00) fmt.Println(ShowRegionInfo(huqiu)) kunshan := NewCities("昆山市") kunshan.Add(NewTown("玉山镇", 60, 1200.00), NewTown("周庄镇", 68, 1900.00), NewTown("花桥镇", 78, 2200.00)) fmt.Println(ShowRegionInfo(kunshan)) changshu := NewCities("常熟市") changshu.Add(NewTown("沙家浜镇", 55, 1100.00), NewTown("古里镇", 59, 1300.00), NewTown("辛庄镇", 68, 2100.00)) fmt.Println(ShowRegionInfo(changshu)) suzhou := NewCities("苏州市") suzhou.Add(gusu, wuzhong, huqiu, kunshan, changshu) fmt.Println(ShowRegionInfo(suzhou))}func ShowRegionInfo(region Region) string { return fmt.Sprintf("%s, 人口:%d万, GDP:%.2f亿", region.Name(), region.Population(), region.GDP())}
运行后果
=== RUN TestComposite姑苏区, 人口:100万, GDP:2000.00亿吴中区, 人口:150万, GDP:2600.00亿虎丘区, 人口:80万, GDP:1800.00亿昆山市, 人口:206万, GDP:5300.00亿常熟市, 人口:182万, GDP:4500.00亿苏州市, 人口:718万, GDP:16200.00亿--- PASS: TestComposite (0.00s)PASS
装璜模式
(一)概念
装璜是一种构造设计模式,容许你通过将对象放入非凡封装对象中来为原对象减少新的行为。
因为指标对象和装璜器遵循同一接口,因而你可用装璜来对对象进行有限次的封装。后果对象将取得所有封装器叠加而来的行为。
(二)示例
地铁进站的过程个别状况下只须要买票,检票进站,然而如果你是带行李,就须要进行安全检查,如果是疫情期间,就须要进行疫情防护查看,比方戴口罩、测量体温等,这里买票进站相当于通用进站流程,安检及防疫查看就相当于增强的润饰行为。
润饰器实现
package decoratorimport "fmt"// Station 车站,润饰器模式对立接口type Station interface { Enter() string // 进站}// subwayStation 地铁站type subwayStation struct { name string}// NewSubwayStation 创立指定站名地铁站func NewSubwayStation(name string) *subwayStation { return &subwayStation{ name: name, }}// Enter 进地铁站func (s *subwayStation) Enter() string { return fmt.Sprintf("买票进入%s地铁站。", s.name)}// securityCheckDecorator 进站安检润饰器type securityCheckDecorator struct { station Station}func NewSecurityCheckDecorator(station Station) *securityCheckDecorator { return &securityCheckDecorator{ station: station, }}func (s *securityCheckDecorator) Enter() string { return "行李通过安检;" + s.station.Enter()}// epidemicProtectionDecorator 进站疫情防护润饰器type epidemicProtectionDecorator struct { station Station}func NewEpidemicProtectionDecorator(station Station) *epidemicProtectionDecorator { return &epidemicProtectionDecorator{ station: station, }}func (e *epidemicProtectionDecorator) Enter() string { return "测量体温,佩戴口罩;" + e.station.Enter()}
测试代码
package decoratorimport ( "fmt" "testing")func TestDecorator(t *testing.T) { xierqiStation := NewSubwayStation("西二旗") fmt.Println(EnhanceEnterStationProcess(xierqiStation, false, false).Enter()) fmt.Println(EnhanceEnterStationProcess(xierqiStation, true, false).Enter()) fmt.Println(EnhanceEnterStationProcess(xierqiStation, true, true).Enter())}// EnhanceEnterStationProcess 依据是否有行李,是否处于疫情,减少进站流程func EnhanceEnterStationProcess(station Station, hasLuggage bool, hasEpidemic bool) Station { if hasLuggage { station = NewSecurityCheckDecorator(station) } if hasEpidemic { station = NewEpidemicProtectionDecorator(station) } return station}
运行后果
=== RUN TestDecorator买票进入西二旗地铁站。行李通过安检;买票进入西二旗地铁站。测量体温,佩戴口罩;行李通过安检;买票进入西二旗地铁站。--- PASS: TestDecorator (0.00s)PASS
外观模式
(一)概念
外观是一种结构型设计模式,能为简单零碎、程序库或框架提供一个简略 (但无限) 的接口。
只管外观模式升高了程序的整体复杂度,但它同时也有助于将不须要的依赖挪动到同一个地位。
(二)示例
用户在淘宝电商零碎买商品时,只须要选好商品在结算页点击提交即可实现下单;在客户端零碎仅须要一个创立订单的办法,然而整个订单的生成须要很多步骤,比方查问用户配送地址,查问商品价格,应用优惠券,扣减商品库存,领取相应价格等。
淘宝电商零碎
package facadeimport "fmt"// TaobaoFacade 淘宝网站门面,在淘宝网站下单波及到多个零碎配合调用,包含用户零碎,商品零碎,优惠券零碎,库存零碎,领取零碎,最终生成订单type TaobaoFacade struct { userService *UserService productService *ProductService couponService *CouponService stockService *StockService paymentService *PaymentService}// NewTaobaoFacade 创立淘宝网站func NewTaobaoFacade() *TaobaoFacade { return &TaobaoFacade{ userService: &UserService{}, productService: &ProductService{ products: map[string]float64{"笔记本电脑": 6666.66}, }, couponService: &CouponService{}, stockService: &StockService{}, paymentService: &PaymentService{}, }}// CreateOrder 依据用户名,商品名,商品数量生成购买订单func (t *TaobaoFacade) CreateOrder(userName string, productName string, count int) string { // 应用优惠券 couponInfo := t.couponService.useCoupon() // 扣减库存 stockInfo := t.stockService.decreaseFor(productName, count) // 计算商品总价 sumPrice := t.productService.getProductPrice(productName) * float64(count) // 领取价格 payInfo := t.paymentService.pay(sumPrice) return fmt.Sprintf("用户%s,购买了%d件%s商品,%s,%s,%s,送货到%s", userName, count, productName, couponInfo, stockInfo, payInfo, t.userService.getUserAddress(userName))}// UserService 用户零碎type UserService struct{}func (u *UserService) getUserAddress(userName string) string { return fmt.Sprintf("%s地址是:北京市海淀区中关村大巷,1号院2号楼3单元402", userName)}// ProductService 商品零碎type ProductService struct { products map[string]float64}func (p *ProductService) getProductPrice(productName string) float64 { return p.products[productName]}// CouponService 优惠券零碎type CouponService struct{}func (c *CouponService) useCoupon() string { return "应用满100减20优惠券"}// StockService 库存零碎type StockService struct{}func (s *StockService) decreaseFor(productName string, count int) string { return fmt.Sprintf("扣减%d件%s商品库存", count, productName)}// PaymentService 领取零碎type PaymentService struct{}func (p *PaymentService) pay(amount float64) string { return fmt.Sprintf("领取金额%.2f", amount)}
测试程序
package facadeimport ( "fmt" "testing")func TestFacade(t *testing.T) { // 通过门面模式,暗藏下单过程中,后端多个零碎的简单交互 taobao := NewTaobaoFacade() fmt.Println(taobao.CreateOrder("张三", "笔记本电脑", 1))}
运行后果
=== RUN TestFacade用户张三,购买了1件笔记本电脑商品,应用满100减20优惠券,扣减1件笔记本电脑商品库存,领取金额6666.66,送货到张三地址是:北京市海淀区中关村大巷,1号院2号楼3单元402--- PASS: TestFacade (0.00s)PASS
享元模式
(一)概念
享元是一种结构型设计模式,它容许你在耗费大量内存的状况下反对大量对象。
模式通过共享多个对象的局部状态来实现上述性能。换句话来说,享元会将不同对象的雷同数据进行缓存以节俭内存。
(二)示例
北京出租车调度零碎,须要每隔一分钟记录一下全市出租车的地位信息,假如为了进步零碎响应速度,近一天的数据须要存储在内存中,每个地位信息包含出租车辆信息及地位信息,地位信息在零碎中就是一个(x,y)坐标,车辆信息包含车的号牌,色彩,品牌和所属公司,在调度零碎存储的出租车行驶轨迹中,地位是实时在变动的,但车辆信息就能够通过享元模式共用一个对象援用,来缩小内存耗费。
出租车享元对象
package flyweightimport ( "fmt")// Taxi 出租车,享元对象,保留不变的外在属性信息type Taxi struct { licensePlate string // 车牌 color string // 色彩 brand string // 汽车品牌 company string // 所属公司}// LocateFor 获取定位信息func (t *Taxi) LocateFor(monitorMap string, x, y int) string { return fmt.Sprintf("%s,对于车牌号%s,%s,%s品牌,所属%s公司,定位(%d,%d)", monitorMap, t.licensePlate, t.color, t.brand, t.company, x, y)}// taxiFactoryInstance 出租车工厂单例var taxiFactoryInstance = &TaxiFactory{ taxis: make(map[string]*Taxi),}// GetTaxiFactory 获取出租车工厂单例func GetTaxiFactory() *TaxiFactory { return taxiFactoryInstance}// TaxiFactory 出租车工厂类type TaxiFactory struct { taxis map[string]*Taxi // key为车牌号}// getTaxi 获取出租车func (f *TaxiFactory) getTaxi(licensePlate, color, brand, company string) *Taxi { if _, ok := f.taxis[licensePlate]; !ok { f.taxis[licensePlate] = &Taxi{ licensePlate: licensePlate, color: color, brand: brand, company: company, } } return f.taxis[licensePlate]}
出租车调度零碎
package flyweightimport "bytes"// TaxiPosition 出租车地位信息 x,y为外在数据信息,taxi为外在数据信息(享元对象)type TaxiPosition struct { x int y int taxi *Taxi}func NewTaxiPosition(taxi *Taxi, x, y int) *TaxiPosition { return &TaxiPosition{ taxi: taxi, x: x, y: y, }}// LocateFor 定位信息func (p *TaxiPosition) LocateFor(monitorMap string) string { return p.taxi.LocateFor(monitorMap, p.x, p.y)}// TaxiDispatcher 出租车调度零碎type TaxiDispatcher struct { name string traces map[string][]*TaxiPosition // 存储出租车当天轨迹信息,key为车牌号}func NewTaxiDispatcher(name string) *TaxiDispatcher { return &TaxiDispatcher{ name: name, traces: make(map[string][]*TaxiPosition), }}// AddTrace 增加轨迹func (t *TaxiDispatcher) AddTrace(licensePlate, color, brand, company string, x, y int) { taxi := GetTaxiFactory().getTaxi(licensePlate, color, brand, company) t.traces[licensePlate] = append(t.traces[licensePlate], NewTaxiPosition(taxi, x, y))}// ShowTraces 显示轨迹func (t *TaxiDispatcher) ShowTraces(licensePlate string) string { bytesBuf := bytes.Buffer{} for _, trace := range t.traces[licensePlate] { bytesBuf.WriteString(trace.LocateFor(t.name)) bytesBuf.WriteByte('\n') } return bytesBuf.String()}
测试程序
package flyweightimport ( "fmt" "testing")func TestFlyweight(t *testing.T) { dispatcher := NewTaxiDispatcher("北京市出租车调度零碎") dispatcher.AddTrace("京B.123456", "黄色", "北京古代", "北汽", 10, 20) dispatcher.AddTrace("京B.123456", "黄色", "北京古代", "北汽", 20, 30) dispatcher.AddTrace("京B.123456", "黄色", "北京古代", "北汽", 30, 40) dispatcher.AddTrace("京B.123456", "黄色", "北京古代", "北汽", 40, 50) dispatcher.AddTrace("京B.567890", "红色", "一汽大众", "首汽", 20, 40) dispatcher.AddTrace("京B.567890", "红色", "一汽大众", "首汽", 50, 50) fmt.Println(dispatcher.ShowTraces("京B.123456")) fmt.Println(dispatcher.ShowTraces("京B.567890"))}
运行后果
=== RUN TestFlyweight北京市出租车调度零碎,对于车牌号京B.123456,黄色,北京古代品牌,所属北汽公司,定位(10,20)北京市出租车调度零碎,对于车牌号京B.123456,黄色,北京古代品牌,所属北汽公司,定位(20,30)北京市出租车调度零碎,对于车牌号京B.123456,黄色,北京古代品牌,所属北汽公司,定位(30,40)北京市出租车调度零碎,对于车牌号京B.123456,黄色,北京古代品牌,所属北汽公司,定位(40,50)北京市出租车调度零碎,对于车牌号京B.567890,红色,一汽大众品牌,所属首汽公司,定位(20,40)北京市出租车调度零碎,对于车牌号京B.567890,红色,一汽大众品牌,所属首汽公司,定位(50,50)--- PASS: TestFlyweight (0.00s)PASS
代理模式
(一)概念
代理是一种结构型设计模式,让你能提供实在服务对象的替代品给客户端应用。代理接管客户端的申请并进行一些解决 (访问控制和缓存等), 而后再将申请传递给服务对象。
代理对象领有和服务对象雷同的接口,这使得当其被传递给客户端时可与实在对象调换。
润饰与代理是十分类似的设计模式,都是基于组合设计准则,也就是说一个对象应该将局部工作委派给另一个对象。但两者之间不同点我认为是,润饰器模式总是要执行服务对象,对于执行之前或执行之后后果进行增强,服务对象根本是客户端创立好再嵌套外层的润饰对象;而代理模式不肯定执行服务对象,有可能通过缓存,提早加载等没有拜访服务对象,同时服务对象什么时候创立也是由代理类决定的。
(二)示例
房屋中介代理帮忙房东卖房子,这个过程就是一个代理模式的过程,中介会收集尽量多的卖房信息,并通过各种渠道公布,同时中介会随时带客户看房,并初步切磋价格,如果达成初步购买动向,才会约房东探讨屋宇价格,最初签约卖房;房屋中介与房东都实现卖房接口,中介会提前坐一些前期工作,如果都没问题,才会约房东执行真正的签约卖房流程。
房屋中介卖房
package proxyimport ( "bytes" "fmt")// HouseSeller 屋宇出售者type HouseSeller interface { SellHouse(address string, buyer string) string}// houseProxy 房产中介代理type houseProxy struct { houseSeller HouseSeller}func NewHouseProxy(houseSeller HouseSeller) *houseProxy { return &houseProxy{ houseSeller: houseSeller, }}// SellHouse 中介卖房,看房->初步谈价->最终和房东签协定func (h *houseProxy) SellHouse(address string, buyer string) string { buf := bytes.Buffer{} buf.WriteString(h.viewHouse(address, buyer) + "\n") buf.WriteString(h.preBargain(address, buyer) + "\n") buf.WriteString(h.houseSeller.SellHouse(address, buyer)) return buf.String()}// viewHouse 看房介绍根本状况func (h *houseProxy) viewHouse(address string, buyer string) string { return fmt.Sprintf("带买家%s看位于%s的屋宇,并介绍根本状况", buyer, address)}// preBargain 初步沟通价格func (h *houseProxy) preBargain(address string, buyer string) string { return fmt.Sprintf("讨价还价后,初步达成购买动向")}// houseOwner 房东type houseOwner struct{}// SellHouse 房东卖房,切磋价格,签订购房协定func (h *houseOwner) SellHouse(address string, buyer string) string { return fmt.Sprintf("最终切磋价格后,与%s签订购买地址为%s的购房协定。", buyer, address)}
测试程序
package proxyimport ( "fmt" "testing")func TestProxy(t *testing.T) { proxy := NewHouseProxy(&houseOwner{}) fmt.Println(proxy.SellHouse("北京市海淀区中关村大巷,2号院1号楼4单元502室", "李四"))}
运行后果
=== RUN TestProxy带买家李四看位于北京市海淀区中关村大巷,2号院1号楼4单元502室的屋宇,并介绍根本状况讨价还价后,初步达成购买动向最终切磋价格后,与李四签订购买地址为北京市海淀区中关村大巷,2号院1号楼4单元502室的购房协定。--- PASS: TestProxy (0.00s)PASS
工厂办法模式
(一)概念
工厂办法模式是一种创立型设计模式,其在父类中提供一个创建对象的办法, 容许子类决定实例化对象的类型。
(二)示例
摊煎饼的小贩须要先摊个煎饼,再卖出去,摊煎饼就能够类比为一个工厂办法,依据顾客的爱好摊出不同口味的煎饼。
接口
package factorymethod// Pancake 煎饼type Pancake interface { // ShowFlour 煎饼应用的面粉 ShowFlour() string // Value 煎饼价格 Value() float32}// PancakeCook 煎饼厨师type PancakeCook interface { // MakePancake 摊煎饼 MakePancake() Pancake}// PancakeVendor 煎饼小贩type PancakeVendor struct { PancakeCook}// NewPancakeVendor ...func NewPancakeVendor(cook PancakeCook) *PancakeVendor { return &PancakeVendor{ PancakeCook: cook, }}// SellPancake 卖煎饼,先摊煎饼,再卖func (vendor *PancakeVendor) SellPancake() (money float32) { return vendor.MakePancake().Value()}
实现
各种面的煎饼实现
package factorymethod// cornPancake 玉米面煎饼type cornPancake struct{}// NewCornPancake ...func NewCornPancake() *cornPancake { return &cornPancake{}}func (cake *cornPancake) ShowFlour() string { return "玉米面"}func (cake *cornPancake) Value() float32 { return 5.0}// milletPancake 小米面煎饼type milletPancake struct{}func NewMilletPancake() *milletPancake { return &milletPancake{}}func (cake *milletPancake) ShowFlour() string { return "小米面"}func (cake *milletPancake) Value() float32 { return 8.0}
制作各种口味煎饼的工厂办法实现
package factorymethod// cornPancakeCook 制作玉米面煎饼厨师type cornPancakeCook struct{}func NewCornPancakeCook() *cornPancakeCook { return &cornPancakeCook{}}func (cook *cornPancakeCook) MakePancake() Pancake { return NewCornPancake()}// milletPancakeCook 制作小米面煎饼厨师type milletPancakeCook struct{}func NewMilletPancakeCook() *milletPancakeCook { return &milletPancakeCook{}}func (cook *milletPancakeCook) MakePancake() Pancake { return NewMilletPancake()}
使用
package factorymethodimport ( "fmt" "testing")func TestFactoryMethod(t *testing.T) { pancakeVendor := NewPancakeVendor(NewCornPancakeCook()) fmt.Printf("Corn pancake value is %v\n", pancakeVendor.SellPancake()) pancakeVendor = NewPancakeVendor(NewMilletPancakeCook()) fmt.Printf("Millet pancake value is %v\n", pancakeVendor.SellPancake())}
输入:
=== RUN TestFactoryMethodCorn pancake value is 5Millet pancake value is 8--- PASS: TestFactoryMethod (0.00s)PASS
形象工厂模式
(一)概念
形象工厂是一种创立型设计模式,它能创立一系列相干的对象,而无需指定其具体类。
形象工厂定义了用于创立不同产品的接口,但将理论的创立工作留给了具体工厂类。每个工厂类型都对应一个特定的产品变体。
在创立产品时,客户端代码调用的是工厂对象的构建办法,而不是间接调用构造函数 ( new操作符)。因为一个工厂对应一种产品变体,因而它创立的所有产品都可互相兼容。
客户端代码仅通过其形象接口与工厂和产品进行交互。该接口容许同一客户端代码与不同产品进行交互。你只需创立一个具体工厂类并将其传递给客户端代码即可。
(二)示例
厨师筹备一餐时,会别离做吃的和喝的,依据早、中、晚三餐饮食习惯,会别离制作不同的饮食,厨师就相当于形象工厂,制作三餐的不同烹饪形式就好比不同形象工厂的实现。
接口
package abstractfactory// Cook 厨师接口,形象工厂type Cook interface { // MakeFood 制作主食 MakeFood() Food // MakeDrink 制作饮品 MakeDrink() Drink}// Food 主食接口type Food interface { // Eaten 被吃 Eaten() string}// Drink 饮品接口type Drink interface { // Drunk 被喝 Drunk() string}
实现
三餐不同厨师接口的实现
package abstractfactory// breakfastCook 早餐厨师type breakfastCook struct{}func NewBreakfastCook() *breakfastCook { return &breakfastCook{}}func (b *breakfastCook) MakeFood() Food { return &cakeFood{"切片面包"}}func (b *breakfastCook) MakeDrink() Drink { return &gruelDrink{"小米粥"}}// lunchCook 午餐厨师type lunchCook struct{}func NewLunchCook() *lunchCook { return &lunchCook{}}func (l *lunchCook) MakeFood() Food { return &dishFood{"烤全羊"}}func (l *lunchCook) MakeDrink() Drink { return &sodaDrink{"冰镇可口可乐"}}// dinnerCook 晚餐厨师type dinnerCook struct{}func NewDinnerCook() *dinnerCook { return &dinnerCook{}}func (d *dinnerCook) MakeFood() Food { return &noodleFood{"大盘鸡拌面"}}func (d *dinnerCook) MakeDrink() Drink { return &soupDrink{"西红柿鸡蛋汤"}}
不同吃的
package abstractfactoryimport "fmt"// cakeFood 蛋糕type cakeFood struct { cakeName string}func (c *cakeFood) Eaten() string { return fmt.Sprintf("%v被吃", c.cakeName)}// dishFood 菜肴type dishFood struct { dishName string}func (d *dishFood) Eaten() string { return fmt.Sprintf("%v被吃", d.dishName)}// noodleFood 面条type noodleFood struct { noodleName string}func (n *noodleFood) Eaten() string { return fmt.Sprintf("%v被吃", n.noodleName)}
不同喝的
package abstractfactoryimport "fmt"// gruelDrink 粥type gruelDrink struct { gruelName string}func (g *gruelDrink) Drunk() string { return fmt.Sprintf("%v被喝", g.gruelName)}// sodaDrink 汽水type sodaDrink struct { sodaName string}func (s *sodaDrink) Drunk() string { return fmt.Sprintf("%v被喝", s.sodaName)}// soupDrink 汤type soupDrink struct { soupName string}func (s *soupDrink) Drunk() string { return fmt.Sprintf("%v被喝", s.soupName)}
使用
package abstractfactoryimport ( "fmt" "testing")func TestAbstractFactory(t *testing.T) { fmt.Printf("breakfast: %v\n", HaveMeal(NewBreakfastCook())) fmt.Printf("lunch: %v\n", HaveMeal(NewLunchCook())) fmt.Printf("dinner: %v\n", HaveMeal(NewDinnerCook()))}// HaveMeal 吃饭func HaveMeal(cook Cook) string { return fmt.Sprintf("%s %s", cook.MakeFood().Eaten(), cook.MakeDrink().Drunk())}
输入
=== RUN TestAbstractFactorybreakfast: 切片面包被吃 小米粥被喝lunch: 烤全羊被吃 冰镇可口可乐被喝dinner: 大盘鸡拌面被吃 西红柿鸡蛋汤被喝--- PASS: TestAbstractFactory (0.00s)PASS
生成器模式
(一)概念
生成器是一种创立型设计模式,使你可能分步骤创立简单对象。
与其余创立型模式不同,生成器不要求产品领有通用接口。这使得用雷同的创立过程生成不同的产品成为可能。
(二)示例
还是摊煎饼的例子,摊煎饼分为四个步骤,1放面糊、2放鸡蛋、3放调料、4放薄脆,通过四个创立过程,制作好一个煎饼,这个摊煎饼的过程就好比煎饼生成器接口,不同生成器的实现就相当于摊不同品类的煎饼,比方失常的煎饼,衰弱的煎饼(可能用的是细粮面、柴鸡蛋、非油炸薄脆、不放酱等),生成器接口办法也能够通过参数管制煎饼的大小,比方放两勺面糊,放2个鸡蛋等。
生成器的使用者为了防止每次都调用雷同的构建步骤,也能够通过包装类固定几种构建过程,生成几类罕用的产品,就如同摊煎饼有几类常卖固定成品,比方一般的,加两个鸡蛋的,不要香菜的等等,这几类固定构建过程提前定制好,间接通过简略工厂办法就间接创立,如果用户再须要细粒度的定制构建,再通过生成器创立。
接口
package builder// Quantity 重量type Quantity intconst ( Small Quantity = 1 Middle Quantity = 5 Large Quantity = 10)type PancakeBuilder interface { // PutPaste 放面糊 PutPaste(quantity Quantity) // PutEgg 放鸡蛋 PutEgg(num int) // PutWafer 放薄脆 PutWafer() // PutFlavour 放调料 Coriander香菜,Shallot葱 Sauce酱 PutFlavour(hasCoriander, hasShallot, hasSauce bool) // Build 摊煎饼 Build() *Pancake}// Pancake 煎饼type Pancake struct { pasteQuantity Quantity // 面糊重量 eggNum int // 鸡蛋数量 wafer string // 薄脆 hasCoriander bool // 是否放香菜 hasShallot bool // 是否放葱 hasSauce bool // 是否放酱}
实现
失常煎饼创立器
package buildertype normalPancakeBuilder struct { pasteQuantity Quantity // 面糊量 eggNum int // 鸡蛋数量 friedWafer string // 油炸薄脆 hasCoriander bool // 是否放香菜 hasShallot bool // 是否放葱 hasHotSauce bool // 是否放辣味酱}func NewNormalPancakeBuilder() *normalPancakeBuilder { return &normalPancakeBuilder{}}func (n *normalPancakeBuilder) PutPaste(quantity Quantity) { n.pasteQuantity = quantity}func (n *normalPancakeBuilder) PutEgg(num int) { n.eggNum = num}func (n *normalPancakeBuilder) PutWafer() { n.friedWafer = "油炸的薄脆"}func (n *normalPancakeBuilder) PutFlavour(hasCoriander, hasShallot, hasSauce bool) { n.hasCoriander = hasCoriander n.hasShallot = hasShallot n.hasHotSauce = hasSauce}func (n *normalPancakeBuilder) Build() *Pancake { return &Pancake{ pasteQuantity: n.pasteQuantity, eggNum: n.eggNum, wafer: n.friedWafer, hasCoriander: n.hasCoriander, hasShallot: n.hasShallot, hasSauce: n.hasHotSauce, }}
衰弱煎饼创立器
package buildertype healthyPancakeBuilder struct { milletPasteQuantity Quantity // 小米面糊量 chaiEggNum int // 柴鸡蛋数量 nonFriedWafer string // 非油炸薄脆 hasCoriander bool // 是否放香菜 hasShallot bool // 是否放葱}func NewHealthyPancakeBuilder() *healthyPancakeBuilder { return &healthyPancakeBuilder{}}func (n *healthyPancakeBuilder) PutPaste(quantity Quantity) { n.milletPasteQuantity = quantity}func (n *healthyPancakeBuilder) PutEgg(num int) { n.chaiEggNum = num}func (n *healthyPancakeBuilder) PutWafer() { n.nonFriedWafer = "非油炸的薄脆"}func (n *healthyPancakeBuilder) PutFlavour(hasCoriander, hasShallot, _ bool) { n.hasCoriander = hasCoriander n.hasShallot = hasShallot}func (n *healthyPancakeBuilder) Build() *Pancake { return &Pancake{ pasteQuantity: n.milletPasteQuantity, eggNum: n.chaiEggNum, wafer: n.nonFriedWafer, hasCoriander: n.hasCoriander, hasShallot: n.hasShallot, hasSauce: false, }}
煎饼生成器的封装类-厨师
package builder// PancakeCook 摊煎饼徒弟type PancakeCook struct { builder PancakeBuilder}func NewPancakeCook(builder PancakeBuilder) *PancakeCook { return &PancakeCook{ builder: builder, }}// SetPancakeBuilder 从新设置煎饼结构器func (p *PancakeCook) SetPancakeBuilder(builder PancakeBuilder) { p.builder = builder}// MakePancake 摊一个个别煎饼func (p *PancakeCook) MakePancake() *Pancake { p.builder.PutPaste(Middle) p.builder.PutEgg(1) p.builder.PutWafer() p.builder.PutFlavour(true, true, true) return p.builder.Build()}// MakeBigPancake 摊一个巨无霸煎饼func (p *PancakeCook) MakeBigPancake() *Pancake { p.builder.PutPaste(Large) p.builder.PutEgg(3) p.builder.PutWafer() p.builder.PutFlavour(true, true, true) return p.builder.Build()}// MakePancakeForFlavour 摊一个自选调料霸煎饼func (p *PancakeCook) MakePancakeForFlavour(hasCoriander, hasShallot, hasSauce bool) *Pancake { p.builder.PutPaste(Large) p.builder.PutEgg(3) p.builder.PutWafer() p.builder.PutFlavour(hasCoriander, hasShallot, hasSauce) return p.builder.Build()}
- 使用
package builderimport ( "fmt" "testing")func TestBuilder(t *testing.T) { pancakeCook := NewPancakeCook(NewNormalPancakeBuilder()) fmt.Printf("摊一个一般煎饼 %#v\n", pancakeCook.MakePancake()) pancakeCook.SetPancakeBuilder(NewHealthyPancakeBuilder()) fmt.Printf("摊一个衰弱的加量煎饼 %#v\n", pancakeCook.MakeBigPancake())}
输入
=== RUN TestBuilder摊一个一般煎饼 &builder.Pancake{pasteQuantity:5, eggNum:1, wafer:"油炸的薄脆", hasCoriander:true, hasShallot:true, hasSauce:true}摊一个衰弱的加量煎饼 &builder.Pancake{pasteQuantity:10, eggNum:3, wafer:"非油炸的薄脆", hasCoriander:true, hasShallot:true, hasSauce:false}--- PASS: TestBuilder (0.00s)PASS
原型模式
(一)概念
原型是一种创立型设计模式,使你可能复制对象,甚至是简单对象,而又无需使代码依赖它们所属的类。
所有的原型类都必须有一个通用的接口, 使得即便在对象所属的具体类未知的状况下也能复制对象。原型对象能够生成本身的残缺正本, 因为雷同类的对象能够互相拜访对方的公有成员变量。
(二)示例
纸质文件能够通过复印机轻松拷贝出多份,设置Paper接口,蕴含读取文件内容和克隆文件两个办法。同时申明两个类报纸(Newspaper)和简历(Resume)实现了Paper接口,通过复印机(Copier)复印出两类文件的正本,并读取文件正本内容。
接口实现
package prototypeimport ( "bytes" "fmt" "io")// Paper 纸张,蕴含读取内容的办法,拷贝纸张的办法,作为原型模式接口type Paper interface { io.Reader Clone() Paper}// Newspaper 报纸 实现原型接口type Newspaper struct { headline string content string}func NewNewspaper(headline string, content string) *Newspaper { return &Newspaper{ headline: headline, content: content, }}func (np *Newspaper) Read(p []byte) (n int, err error) { buf := bytes.NewBufferString(fmt.Sprintf("headline:%s,content:%s", np.headline, np.content)) return buf.Read(p)}func (np *Newspaper) Clone() Paper { return &Newspaper{ headline: np.headline + "_copied", content: np.content, }}// Resume 简历 实现原型接口type Resume struct { name string age int experience string}func NewResume(name string, age int, experience string) *Resume { return &Resume{ name: name, age: age, experience: experience, }}func (r *Resume) Read(p []byte) (n int, err error) { buf := bytes.NewBufferString(fmt.Sprintf("name:%s,age:%d,experience:%s", r.name, r.age, r.experience)) return buf.Read(p)}func (r *Resume) Clone() Paper { return &Resume{ name: r.name + "_copied", age: r.age, experience: r.experience, }}
使用
package prototypeimport ( "fmt" "reflect" "testing")func TestPrototype(t *testing.T) { copier := NewCopier("云打印机") oneNewspaper := NewNewspaper("Go是最好的编程语言", "Go语言十大劣势") oneResume := NewResume("小明", 29, "5年码农") otherNewspaper := copier.copy(oneNewspaper) copyNewspaperMsg := make([]byte, 100) byteSize, _ := otherNewspaper.Read(copyNewspaperMsg) fmt.Println("copyNewspaperMsg:" + string(copyNewspaperMsg[:byteSize])) otherResume := copier.copy(oneResume) copyResumeMsg := make([]byte, 100) byteSize, _ = otherResume.Read(copyResumeMsg) fmt.Println("copyResumeMsg:" + string(copyResumeMsg[:byteSize]))}// Copier 复印机type Copier struct { name string}func NewCopier(n string) *Copier { return &Copier{name: n}}func (c *Copier) copy(paper Paper) Paper { fmt.Printf("copier name:%v is copying:%v ", c.name, reflect.TypeOf(paper).String()) return paper.Clone()}
输入
=== RUN TestPrototypecopier name:云打印机 is copying:*prototype.Newspaper copyNewspaperMsg:headline:Go是最好的编程语言_copied,content:Go语言十大劣势copier name:云打印机 is copying:*prototype.Resume copyResumeMsg:name:小明_copied,age:29,experience:5年码农--- PASS: TestPrototype (0.00s)PASS
单例模式
(一)概念
单例是一种创立型设计模式,让你可能保障一个类只有一个实例,并提供一个拜访该实例的全局节点。
单例领有与全局变量雷同的优缺点。只管它们十分有用,但却会毁坏代码的模块化个性。
(二)示例
通过地球对象实现单例,earth不能导出,通过TheEarth办法拜访全局惟一实例,并通过sync.Once实现多协程下一次加载。
接口实现
package singletonimport "sync"var once sync.Once// 不可导出对象type earth struct { desc string}func (e *earth) String() string { return e.desc}// theEarth 地球单实例var theEarth *earth// TheEarth 获取地球单实例func TheEarth() *earth { if theEarth == nil { once.Do(func() { theEarth = &earth{ desc: "漂亮的地球,孕育了生命。", } }) } return theEarth}
使用
package singletonimport ( "fmt" "testing")func TestSingleton(t *testing.T) { fmt.Println(TheEarth().String())}
输入
=== RUN TestSingleton漂亮的地球,孕育了生命。--- PASS: TestSingleton (0.00s)PASS