【golang设计模式】Golang设计模式详解三

十一、组合模式
组合模式统一对象和对象集,使得使用相同接口使用对象和对象集。

组合模式常用于树状结构,用于统一叶子节点和树节点的访问,并且可以用于应用某一操作到所有子节点。

composite.go

package composite

import "fmt"

type Component interface {
    Parent() Component
    SetParent(Component)
    Name() string
    SetName(string)
    AddChild(Component)
    Print(string)
}

const (
    LeafNode = iota
    CompositeNode
)

func NewComponent(kind int, name string) Component {
    var c Component
    switch kind {
    case LeafNode:
        c = NewLeaf()
    case CompositeNode:
        c = NewComposite()
    }

    c.SetName(name)
    return c
}

type component struct {
    parent Component
    name   string
}

func (c *component) Parent() Component {
    return c.parent
}

func (c *component) SetParent(parent Component) {
    c.parent = parent
}

func (c *component) Name() string {
    return c.name
}

func (c *component) SetName(name string) {
    c.name = name
}

func (c *component) AddChild(Component) {}

func (c *component) Print(string) {}

type Leaf struct {
    component
}

func NewLeaf() *Leaf {
    return &Leaf{}
}

func (c *Leaf) Print(pre string) {
    fmt.Printf("%s-%s\n", pre, c.Name())
}

type Composite struct {
    component
    childs []Component
}

func NewComposite() *Composite {
    return &Composite{
        childs: make([]Component, 0),
    }
}

func (c *Composite) AddChild(child Component) {
    child.SetParent(c)
    c.childs = append(c.childs, child)
}

func (c *Composite) Print(pre string) {
    fmt.Printf("%s+%s\n", pre, c.Name())
    pre += " "
    for _, comp := range c.childs {
        comp.Print(pre)
    }
}

composite_test.go

package composite

func ExampleComposite() {
    root := NewComponent(CompositeNode, "root")
    c1 := NewComponent(CompositeNode, "c1")
    c2 := NewComponent(CompositeNode, "c2")
    c3 := NewComponent(CompositeNode, "c3")

    l1 := NewComponent(LeafNode, "l1")
    l2 := NewComponent(LeafNode, "l2")
    l3 := NewComponent(LeafNode, "l3")

    root.AddChild(c1)
    root.AddChild(c2)
    c1.AddChild(c3)
    c1.AddChild(l1)
    c2.AddChild(l2)
    c2.AddChild(l3)

    root.Print("")
    // Output:
    // +root
    //  +c1
    //   +c3
    //   -l1
    //  +c2
    //   -l2
    //   -l3
}

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

flyweight.go

package flyweight

import "fmt"

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 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 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())
}

flyweight_test.go

package flyweight

import "testing"

func ExampleFlyweight() {
    viewer := NewImageViewer("image1.png")
    viewer.Display()
    // Output:
    // Display: image data image1.png
}

func TestFlyweight(t *testing.T) {
    viewer1 := NewImageViewer("image1.png")
    viewer2 := NewImageViewer("image1.png")

    if viewer1.ImageFlyweight != viewer2.ImageFlyweight {
        t.Fail()
    }
}

十三、装饰者模式

装饰模式使用对象组合的方式动态改变或增加对象行为。

Go语言借助于匿名组合和非入侵式接口可以很方便实现装饰模式。

使用匿名组合,在装饰器中不必显式定义转调原对象方法。

decorator.go

package decorator

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
}

decorator_test.go

package decorator

import "fmt"

func ExampleDecorator() {
    var c Component = &ConcreteComponent{}
    c = WarpAddDecorator(c, 10)
    c = WarpMulDecorator(c, 8)
    res := c.Calc()

    fmt.Printf("res %d\n", res)
    // Output:
    // res 80
}

十四、桥接模式
桥接模式分离抽象部分和实现部分。使得两部分独立扩展。

桥接模式类似于策略模式,区别在于策略模式封装一系列算法使得算法可以互相替换。

策略模式使抽象部分和实现部分分离,可以独立变化。

bridge.go

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)
}

bridge_test.go

package bridge

func ExampleCommonSMS() {
    m := NewCommonMessage(ViaSMS())
    m.SendMessage("have a drink?", "bob")
    // Output:
    // send have a drink? to bob via SMS
}

func ExampleCommonEmail() {
    m := NewCommonMessage(ViaEmail())
    m.SendMessage("have a drink?", "bob")
    // Output:
    // send have a drink? to bob via Email
}

func ExampleUrgencySMS() {
    m := NewUrgencyMessage(ViaSMS())
    m.SendMessage("have a drink?", "bob")
    // Output:
    // send [Urgency] have a drink? to bob via SMS
}

func ExampleUrgencyEmail() {
    m := NewUrgencyMessage(ViaEmail())
    m.SendMessage("have a drink?", "bob")
    // Output:
    // send [Urgency] have a drink? to bob via Email
}

十五、中介者模式
中介者模式封装对象之间互交,使依赖变的简单,并且使复杂互交简单化,封装在中介者中。

例子中的中介者使用单例模式生成中介者。

中介者的change使用switch判断类型。

mediator.go

package mediator

import (
    "fmt"
    "strings"
)

type CDDriver struct {
    Data string
}

func (c *CDDriver) ReadData() {
    c.Data = "music,image"

    fmt.Printf("CDDriver: reading data %s\n", c.Data)
    GetMediatorInstance().changed(c)
}

type CPU struct {
    Video string
    Sound string
}

func (c *CPU) Process(data string) {
    sp := strings.Split(data, ",")
    c.Sound = sp[0]
    c.Video = sp[1]

    fmt.Printf("CPU: split data with Sound %s, Video %s\n", c.Sound, c.Video)
    GetMediatorInstance().changed(c)
}

type VideoCard struct {
    Data string
}

func (v *VideoCard) Display(data string) {
    v.Data = data
    fmt.Printf("VideoCard: display %s\n", v.Data)
    GetMediatorInstance().changed(v)
}

type SoundCard struct {
    Data string
}

func (s *SoundCard) Play(data string) {
    s.Data = data
    fmt.Printf("SoundCard: play %s\n", s.Data)
    GetMediatorInstance().changed(s)
}

type Mediator struct {
    CD    *CDDriver
    CPU   *CPU
    Video *VideoCard
    Sound *SoundCard
}

var mediator *Mediator

func GetMediatorInstance() *Mediator {
    if mediator == nil {
        mediator = &Mediator{}
    }
    return mediator
}

func (m *Mediator) changed(i interface{}) {
    switch inst := i.(type) {
    case *CDDriver:
        m.CPU.Process(inst.Data)
    case *CPU:
        m.Sound.Play(inst.Sound)
        m.Video.Display(inst.Video)
    }
}

mediator_test.go

package mediator

import "testing"

func TestMediator(t *testing.T) {
    mediator := GetMediatorInstance()
    mediator.CD = &CDDriver{}
    mediator.CPU = &CPU{}
    mediator.Video = &VideoCard{}
    mediator.Sound = &SoundCard{}

    //Tiggle
    mediator.CD.ReadData()

    if mediator.CD.Data != "music,image" {
        t.Fatalf("CD unexpect data %s", mediator.CD.Data)
    }

    if mediator.CPU.Sound != "music" {
        t.Fatalf("CPU unexpect sound data %s", mediator.CPU.Sound)
    }

    if mediator.CPU.Video != "image" {
        t.Fatalf("CPU unexpect video data %s", mediator.CPU.Video)
    }

    if mediator.Video.Data != "image" {
        t.Fatalf("VidoeCard unexpect data %s", mediator.Video.Data)
    }

    if mediator.Sound.Data != "music" {
        t.Fatalf("SoundCard unexpect data %s", mediator.Sound.Data)
    }
}

总结:本次为第三次总结golang设计模式。针对于树形结构可以用适合的组合模式来开发;享元模式针对超多对象且对象内可共用字段,想要节省内存空间的情况;装饰者模式是用对象组合的方式动态改变或增加对象行为;桥接模式是使抽象部分和实现部分相分离,两部分可独立扩展;中介者模式是封装对象间的交互,使得依赖变得简单。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
以下是几种常见的Golang设计模式: 1. 工厂模式(Factory Pattern):用于创建对象的模式,通过定义一个创建对象的接口来实现对象的实例化。 ```go type Shape interface { Draw() } type Circle struct{} func (c *Circle) Draw() { fmt.Println("Drawing a circle") } type Rectangle struct{} func (r *Rectangle) Draw() { fmt.Println("Drawing a rectangle") } type ShapeFactory struct{} func (sf *ShapeFactory) GetShape(shapeType string) Shape { if shapeType == "circle" { return &Circle{} } else if shapeType == "rectangle" { return &Rectangle{} } return nil } func main() { factory := &ShapeFactory{} circle := factory.GetShape("circle") circle.Draw() // 输出:Drawing a circle rectangle := factory.GetShape("rectangle") rectangle.Draw() // 输出:Drawing a rectangle } ``` 2. 单例模式(Singleton Pattern):确保一个类只有一个实例,并提供一个全局访问点。 ```go type Singleton struct{} var instance *Singleton func GetInstance() *Singleton { if instance == nil { instance = &Singleton{} } return instance } func main() { singleton1 := GetInstance() singleton2 := GetInstance() fmt.Println(singleton1 == singleton2) // 输出:true } ``` 3. 观察者模式(Observer Pattern):定义了一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖它的对象都会得到通知并自动更新。 ```go type Subject struct { observers []Observer } func (s *Subject) Attach(observer Observer) { s.observers = append(s.observers, observer) } func (s *Subject) Notify() { for _, observer := range s.observers { observer.Update() } } type Observer interface { Update() } type ConcreteObserver struct{} func (co *ConcreteObserver) Update() { fmt.Println("Observer is updated") } func main() { subject := &Subject{} observer := &ConcreteObserver{} subject.Attach(observer) subject.Notify() // 输出:Observer is updated } ```
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值