go中设计模式之结构型模式

wx5cf612fe3a728 · · 654 次点击 · · 开始浏览    
这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。

外观模式

1. 定义: 外部与一个子系统通信必须通过一个统一的对象进行,为子系统中的一组接口提供一致界面。

2. 代码示例:

// 定义对外API
type API interface {
    Test()
}

func NewAPI() API {
    return apiImpl{newMod()}
}

type apiImpl struct {
    m mod
}

func (a apiImpl) Test() {
    a.m.mod()
}

// 需要交互的内部模块
type mod interface {
    mod()
}

func newMod() mod {
    return modImpl{}
}

type modImpl struct {
}

func (m modImpl) mod() {

}

3. 实现步骤

  • 定义内部模块
  • 定义对外交互接口及实现

4. 使用场景

  • 当要为一个复杂子系统提供一个简单接口时可以使用外观模式。该接口可以满足大多数用户的需求,而且用户也可以越过外观类直接访问子系统。
  • 客户程序与多个子系统之间存在很大的依赖性。引入外观类将子系统与客户以及其他子系统解耦,可以提高子系统的独立性和可移植性。
  • 在层次化结构中,可以使用外观模式定义系统中每一层的入口,层与层之间不直接产生联系,而通过外观类建立联系,降低层之间的耦合度。

5. 优点

对客户屏蔽子系统组件

适配器模式

1. 定义: 将一个接口转换成客户希望的另一个接口。

2. 代码示例:

// 定义被适配的接口
type Adapter interface {
    Request() string
}

type adaptee struct {
}

func (adaptee) Request() string {
}

func NewAdapter() Adapter {
    return &adaptee{}
}

// 定义目标接口
type Target interface {
    TargetRequest() string
}

func New(adapter Adapter) Target {
    return &target{adapter}
}

type target struct {
    Adapter
}

func (t *target) TargetRequest() {
    t.Request()
}

3. 实现步骤

  • 定义被适配的接口和实现
  • 定义目标接口和实现,并且实现接口由被适配接口创建

4. 使用场景

系统需要使用现有的类,而这些类的接口不符合系统的需要。

5. 优点

将目标类和适配者类解耦,通过引入一个适配器类来重用现有的适配者类,而无须修改原有代码。

装饰模式

1. 定义: 动态地给一个对象增加一些额外的职责。

2. 代码示例:

// 定义组件
type Component interface {
    Calc() int
}

type ConcreteComponent struct{}

func (*ConcreteComponent) Calc() int {
    return 0
}

// 定义装饰对象
type MulDecorator struct {
    Component
    num int
}

func WarpMulDecorator(c Component, num int) Component {
    return &MulDecorator{
        Component: c,
        num:       num,
    }
}

func (d *MulDecorator) Calc() int {
    return d.Component.Calc() * d.num
}

type AddDecorator struct {
    Component
    num int
}

func WarpAddDecorator(c Component, num int) Component {
    return &AddDecorator{
        Component: c,
        num:       num,
    }
}

func (d *AddDecorator) Calc() int {
    return d.Component.Calc() + d.num
}

3. 实现步骤

  • 定义组件
  • 定义装饰对象
  • 使用装饰对象生成组件

4. 使用场景

在不影响其他对象的情况下,以动态、透明的方式给单个对象添加职责。

5. 优点

可以通过一种动态的方式来扩展一个对象的功能,通过配置文件可以在运行时选择不同的装饰器,从而实现不同的行为。

享元模式

1. 定义: 享元模式通过共享技术实现相同或相似对象的重用。

2. 代码示例:

// 定义享元对象
type ImageFlyweight struct {
    data string
}

func NewImageFlyweight(filename string) *ImageFlyweight {
    // Load image file
    data := fmt.Sprintf("image data %s", filename)
    return &ImageFlyweight{
        data: data,
    }
}

func (i *ImageFlyweight) Data() string {
    return i.data
}

// 定义享元对象工厂
type ImageFlyweightFactory struct {
    maps map[string]*ImageFlyweight
}

var imageFactory *ImageFlyweightFactory

func GetImageFlyweightFactory() *ImageFlyweightFactory {
    if imageFactory == nil {
        imageFactory = &ImageFlyweightFactory{
            maps: make(map[string]*ImageFlyweight),
        }
    }
    return imageFactory
}

func (f *ImageFlyweightFactory) Get(filename string) *ImageFlyweight {
    image := f.maps[filename]
    if image == nil {
        image = NewImageFlyweight(filename)
        f.maps[filename] = image
    }

    return image
}

type ImageViewer struct {
    *ImageFlyweight
}

func NewImageViewer(filename string) *ImageViewer {
    image := GetImageFlyweightFactory().Get(filename)
    return &ImageViewer{
        ImageFlyweight: image,
    }
}

func (i *ImageViewer) Display() {
    fmt.Printf("Display: %s\n", i.Data())
}

3. 实现步骤

  • 定义享元对象
  • 定义享元工厂
  • 使用享元工厂创建

4. 使用场景

  • 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费。
    对象的大部分状态都可以外部化,可以将这些外部状态传入对象中。
  • 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。

5. 优点

享元模式从对象中剥离出不发生改变且多个实例需要的重复数据,独立出一个享元,使多个对象共享,从而节省内存以及减少对象数量。

代理模式

1. 定义: 给某一个对象提供一个代理,并由代理对象控制对原对象的引用。

2. 代码示例:

package proxy

type Subject interface {
    Do() string
}

type RealSubject struct{}

func (RealSubject) Do() string {
    return "real"
}

type Proxy struct {
    real RealSubject
}

func (p Proxy) Do() string {
    var res string

    // 在调用真实对象之前的工作,检查缓存,判断权限,实例化真实对象等。。
    res += "pre:"

    // 调用真实对象
    res += p.real.Do()

    // 调用之后的操作,如缓存结果,对结果进行处理等。。
    res += ":after"

    return res
}

3. 实现步骤

  • 定义接口
  • 定义实现对象
  • 定义代理实现对象

4. 使用场景

  • 并由代理对象控制对原对象的引用,增加请求注入劫持

5. 优点

代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度。

桥接模式

1. 定义: 给某一个对象提供一个代 理,并由代理对象控制对原对象的引用。

2. 代码示例:

package bridge

import "fmt"

type AbstractMessage interface {
    SendMessage(text, to string)
}

type MessageImplementer interface {
    Send(text, to string)
}

type MessageSMS struct{}

func ViaSMS() MessageImplementer {
    return &MessageSMS{}
}

func (*MessageSMS) Send(text, to string) {
    fmt.Printf("send %s to %s via SMS", text, to)
}

type MessageEmail struct{}

func ViaEmail() MessageImplementer {
    return &MessageEmail{}
}

func (*MessageEmail) Send(text, to string) {
    fmt.Printf("send %s to %s via Email", text, to)
}

type CommonMessage struct {
    method MessageImplementer
}

func NewCommonMessage(method MessageImplementer) *CommonMessage {
    return &CommonMessage{
        method: method,
    }
}

func (m *CommonMessage) SendMessage(text, to string) {
    m.method.Send(text, to)
}

type UrgencyMessage struct {
    method MessageImplementer
}

func NewUrgencyMessage(method MessageImplementer) *UrgencyMessage {
    return &UrgencyMessage{
        method: method,
    }
}

func (m *UrgencyMessage) SendMessage(text, to string) {
    m.method.Send(fmt.Sprintf("[Urgency] %s", text), to)
}

3. 实现步骤

4. 使用场景

5. 优点


有疑问加站长微信联系(非本文作者)

本文来自:51CTO博客

感谢作者:wx5cf612fe3a728

查看原文:go中设计模式之结构型模式

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

654 次点击  
加入收藏 微博
添加一条新回复 (您需要 登录 后才能回复 没有账号 ?)
  • 请尽量让自己的回复能够对别人有帮助
  • 支持 Markdown 格式, **粗体**、~~删除线~~、`单行代码`
  • 支持 @ 本站用户;支持表情(输入 : 提示),见 Emoji cheat sheet
  • 图片支持拖拽、截图粘贴等方式上传