前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >【建议收藏】如何用Go写出优美的代码-Go的设计模式【装饰器模式,门面模式,亨元模式】篇五

【建议收藏】如何用Go写出优美的代码-Go的设计模式【装饰器模式,门面模式,亨元模式】篇五

作者头像
公众号-利志分享
发布2022-12-01 16:04:58
3930
发布2022-12-01 16:04:58
举报
文章被收录于专栏:利志分享利志分享

大家好,我是追麾(hui)。最近比较久没更新原创了,主要是工作上确实太忙。

这是Go的设计模式第五篇,这篇主要分享装饰器模式,门面模式,亨元模式。下面我们来看具体模式。

Go的装饰器模式

业界装饰器模式定义:指在不改变现有对象结构的情况下,向目标对象中动态地添加或删除功能。

装饰器模式优缺点

  • 优点
    • 装饰器模式是对继承进行补充,但比继承更加灵活,能做到即插即用,插拔方式进行实现装饰。
    • 装饰器模式完全遵守开闭原则
  • 缺点
    • 装饰器模式会增加许多对象,过度使用会增加程序的复杂性。

装饰器模式的应用场景

  • 动态地向目标对象添加功能,而不影响到其他同类型的对象。
  • 当对象的功能要求可以动态地添加,也可以再动态地撤销时。

Go装饰器模式实现方式

装饰器模式主要包含以下主要角色。

  1. 抽象构建角色:定义一个抽象接口以规范准备接受附加责任的对象。
  2. 实现抽象构建,通过装饰角色为添加一些职责。
  3. 抽象装饰角色:继承抽象构建,并包含具体构建的实例,通过其子类扩展具体构建的功能。
  4. 具体装饰角色:实现抽奖装饰方法,并给具体构架添加附件的责任。

装饰器模式基于原有的功能做一些增强,下面我们来看一下通过枪的例子来演示一下。

代码语言:javascript
复制
package main

import "fmt"

func main() {
 m := MachineGun{}
 m.Shooting()
 s := SniperRifleGun{}
 s.Shooting()
}

// 抽象构件
type DecorateGunInterface interface {
 Shooting()
}

// 具体构件, 枪射击
type Gun struct {
}

func (g *Gun) Shooting() {
 fmt.Println("枪射击")
}

// 抽象装饰角色, 这里是目标对象添加功能
type MachineDecorator struct {
 Machine Gun
}

// 具体装饰,机关枪
type MachineGun struct {
 Gun MachineDecorator
}

func (m *MachineGun) Shooting() {
 fmt.Println("机关")
 m.Gun.Machine.Shooting()
}

// 具体装饰,狙击枪
type SniperRifleGun struct {
 Gun MachineDecorator
}

func (m *SniperRifleGun) Shooting() {
 fmt.Println("狙击")
 m.Gun.Machine.Shooting()
}

执行结果如下:

代码语言:javascript
复制
机关
枪射击
狙击  
枪射击

‍Go门面模式‍

业界门面模式定义:门面模式又叫外观模式,通过为多个复杂的子系统提供一个一致的统一的接口,而使这些子系统更加容易被访问的模式叫门面模式。

门面模式优缺点

  • 优点:-简化复杂系统的调用过程,无需对子系统进行深入了解,即可完成调用。
    • 降低了系统间的依赖,使耦合关系更低 ; 子系统内部的模块更容易扩展和维护。
    • 层次结构复杂的系统,有些方法需要提供给系统外部调用,有些方法需要在内部使用,将提供给外部的功能定义在门面类中,这样既方便调用,也能将系统内部的细节隐藏起来。
    • 降低了应用层与子系统之间的耦合度。
  • 缺点
    • 系统内部扩展子系统时,容易产生风险
    • 门面模式,扩展子系统时,不符合开闭原则。

门面模式的应用场景

  • 当系统中包含多个子系统,完成一项任务需要多个子系统通力合作,提高子系统的独立性和可移植性。
  • 当一个复杂系统的子系统很多时,门面模式可以为系统设计一个简单的接口供外界访问。

Go门面模式实现方式

门面模式主要由以下角色:

  1. 门面角色:为多个子系统对外提供一个共同的接口。
  2. 子系统角色:实现系统的部分功能,客户可以通过门面角色访问它。
  3. 客户角色:通过一个门面角色访问各个子系统的功能。

下面我们通过一个电商的详情页面的例子来看下门面模式的实现。不同的子系统接口,通过一个门面接口进行整合统一,提供对外服务。

代码语言:javascript
复制
package main

import "fmt"

// 客户角色
func main() {
 GetFacadeDetail()
}

type Product struct {
}

// 子系统角色A
func (p *Product) GetProductInfo() {
 fmt.Println("这里是获取商品详情的信息接口")
}

type Stock struct {
}

// 子系统角色B
func (s *Stock) GetStockInfo() {
 fmt.Println("这里是获取库存信息接口")
}

type Ad struct {
}

// 子系统角色C
func (a *Ad) GetAdInfo() {
 fmt.Println("这里是获取广告营销的信息接口")
}

// 外观角色
func GetFacadeDetail() {
 p := Product{}
 a := Ad{}
 s := Stock{}
 p.GetProductInfo()
 a.GetAdInfo()
 s.GetStockInfo()
 fmt.Println("详情页面所哟的接口...")
}

Go的亨元模式

业界亨元模式定义:通过共享的方式提供数量庞大的细粒度对象的复用,通过共享能减少创建的数据对象,避免大量相似类的开销,从而提供系统资源的利用率。享元模式其实是工厂方法模式的一个改进机制。

亨元模式优缺点

  • 优点
    • 运行时产生大量的相似对象,而这些对象的状态被客户端管理,开发人员想要减少运行时对象生成的数量。
    • 为了提高程序运行效率,将可共享对象的实例共享到所有客户端,这样能够节省程序构造新对象所需要的资源和时间,也能减少对象实例的数量。
    • 缩小内存之外的其余资源占用。
  • 缺点
    • 为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性。

亨元模式的应用场景

  • 缓存共享对象,降低内存消耗。

Go亨元模式实现方式

享元模式的主要角色:

  1. 抽象享元角色:是所有的具体享元类的基类,为具体享元规范需要实现的公共接口,非享元的外部状态以参数的形式通过方法传入。
  2. 具体享元角色:实现抽象享元角色中所规定的接口。
  3. 非享元角色:是不可以共享的外部状态,它以参数的形式注入具体享元的相关方法中。
  4. 享元工厂角色:负责创建和管理享元角色。当客户对象请求一个享元对象时,享元工厂检査系统中是否存在符合要求的享元对象,如果存在则提供给客户;如果不存在的话,则创建一个新的享元对象。

下面我们来看一下例子,我们把枪当成一个具体亨元角色,写一个亨元工厂进行存储亨元角色数据。下面我们来看具体例子。

代码语言:javascript
复制
package main

import (
 "fmt"
 "sync"
)

func main() {
 // 创建亨元
 f := NewFlyWeightPattern()

 // 具体亨元角色
 b := NewGunBase()
 f.SetElement("a1", b)
 // 读取亨元数据
 p := f.GetElement("a1").(GunProperty)
 fmt.Println(p.Shoot())

 // 非享元角色
 b2 := NewSubMachineGun(b, "auto")
 f.SetElement("b1", b2)
 // 读取享元角色数据
 p2 := f.GetElement("b1").(GunProperty)
 fmt.Println(p2.Shoot())
}

// 设计枪属性 具体享元角色
type GunProperty interface {
 // 射击属性
 Shoot() string
}

type GunBase struct {
 ShootType string
}

func NewGunBase() *GunBase {
 return &GunBase{"manual"}
}

func (g *GunBase) Shoot() string {
 return g.ShootType
}

// 冲锋枪
type SubMachineGun struct {
 base      GunProperty
 AutoShoot string
}

func NewSubMachineGun(base GunProperty, shootType string) *SubMachineGun {
 return &SubMachineGun{base, shootType}
}

func (s *SubMachineGun) Shoot() string {
 return s.base.Shoot() + s.AutoShoot
}

// 抽象享元角色
type Element struct {
 value interface{}
}

func NewElement(value interface{}) *Element {
 return &Element{value}
}

// 享元工厂角色
type FlyWeightPattern struct {
 pool map[string]*Element
 m    *sync.RWMutex
}

func (f *FlyWeightPattern) GetElement(key string) interface{} {
 f.m.RLock()
 defer f.m.RUnlock()
 return f.pool[key].value
}

func (f *FlyWeightPattern) SetElement(key string, value interface{}) {
 n := NewElement(value)
 f.m.Lock()
 defer f.m.Unlock()
 f.pool[key] = n
}

func NewFlyWeightPattern() *FlyWeightPattern {
 f := FlyWeightPattern{}
 f.pool = map[string]*Element{}
 f.m = &sync.RWMutex{}
 return &f
}

执行结果如下:

代码语言:javascript
复制
manual
manualauto

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2022-08-08,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 利志分享 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • Go的装饰器模式
  • ‍Go门面模式‍
  • Go的亨元模式
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档