美文网首页程序员设计模式
手撸golang 结构型设计模式 享元模式

手撸golang 结构型设计模式 享元模式

作者: 老罗话编程 | 来源:发表于2021-02-03 11:18 被阅读0次

    手撸golang 结构型设计模式 享元模式

    缘起

    最近复习设计模式
    拜读谭勇德的<<设计模式就该这样学>>
    本系列笔记拟采用golang练习之

    享元模式

    享元模式(Flyweight Pattern)又叫作轻量级模式,是对象池的一种实现。享元模式提供了减少对象数量从而改善应用所需的对象结构的方式。其宗旨是共享细粒度对象,不必为每个访问者都创建一个单独的对象,以此来降低内存的消耗,属于结构型设计模式。
    _

    场景

    • 某火车票查询系统, 可根据发站和到站, 查询余票信息
    • 火车票包含基本信息(发站, 到站, 经停站, 出发时间, 到站时间...)和剩余票数信息
    • 基本信息字段较多, 且只跟发站和到站相关, 因此可采用享元模式进行池化处理
    • 剩余票数信息由于实时变化, 因此由余票服务另外提供

    设计

    • ITicket: 定义车票基本信息接口
    • ITicketRemaining: 继承ITicket, 并添加余票数信息
    • ITicketService: 定义车票信息服务接口
    • ITicketRemainingService: 定义余票信息服务接口. 根据发站和到站, 查询余票信息.
    • tMockTicket: 车票信息实体, 实现ITicket接口
    • tMockTicketService: 车票信息服务, 通过享元模式池化了车票信息.
    • tMockTicketRemaining: 余票信息实体, 实现ITicketRemaining接口
    • tMockTicketRemainingService: 余票信息服务, 通过ITicketService获取车票基本信息. 根据发站和到站, 查询余票信息.

    单元测试

    flyweight_pattern_test.go

    package structural_patterns
    
    import (
        "learning/gooop/structural_patterns/flyweight"
        "testing"
    )
    
    func Test_FlyweightPattern(t *testing.T) {
        from := "福田"
        to := "广州南"
        ticket := flyweight.NewMockTicket(1, from, to, 100)
        flyweight.MockTicketService.Save(ticket)
        flyweight.MockTicketRemainingService.Save(ticket.ID(), 10)
    
        remaining := flyweight.MockTicketRemainingService.Get(from, to)
        t.Logf("from=%s, to=%s, price=%v, remaining=%v\n", remaining.From(), remaining.To(), remaining.Price(), remaining.Remaining())
    }
    
    

    测试输出

    t$ go test -v flyweight_pattern_test.go 
    === RUN   Test_FlyweightPattern
        flyweight_pattern_test.go:16: from=福田, to=广州南, price=100, remaining=10
    --- PASS: Test_FlyweightPattern (0.00s)
    PASS
    ok      command-line-arguments  0.003s
    

    ITicket.go

    定义车票基本信息接口

    package flyweight
    
    // 车票信息
    type ITicket interface {
        ID() int
        From() string
        To() string
        LeavingTime() string
        ArrivalTime() string
        InterList() []string
        Price() float64
    }
    
    

    ITicketRemaining.go

    继承ITicket, 并添加余票数信息

    package flyweight
    
    // 余票信息
    type ITicketRemaining interface {
        ITicket
        Remaining() int
    }
    

    ITicketService.go

    定义车票信息服务接口

    package flyweight
    
    
    type ITicketService interface {
        Get(from string, to string) ITicket
        Save(it ITicket)
    }
    

    ITicketRemainingService.go

    定义余票信息服务接口, 根据发站和到站, 查询余票信息.

    package flyweight
    
    
    type ITicketRemainingService interface {
        Get(from string, to string) ITicketRemaining
        Save(id int, num int)
    }
    

    **

    tMockTicket.go

    车票信息实体, 实现ITicket接口

    package flyweight
    
    import "strings"
    
    type tMockTicket struct {
        iID int
        sFrom string
        sTo string
        sLeavingTime string
        sArrivalTime string
        mInterList []string
        fPrice float64
        iRemaining int
    }
    
    func NewMockTicket(id int, from string, to string, price float64) *tMockTicket {
        return &tMockTicket{
            iID: id,
            sFrom: from,
            sTo: to,
            sLeavingTime: "09:00",
            sArrivalTime: "11:30",
            mInterList: strings.Split("深圳北,虎门", ","),
            fPrice: price,
        }
    }
    
    func (me *tMockTicket) ID() int {
        return me.iID
    }
    
    
    func (me *tMockTicket) From() string {
        return me.sFrom
    }
    
    func (me *tMockTicket) To() string {
        return me.sTo
    }
    
    func (me *tMockTicket) LeavingTime() string {
        return me.sLeavingTime
    }
    
    func (me *tMockTicket) ArrivalTime() string {
        return me.sArrivalTime
    }
    
    
    func (me *tMockTicket) InterList() []string {
        return me.mInterList
    }
    
    
    func (me *tMockTicket) Price() float64 {
        return me.fPrice
    }
    

    tMockTicketService.go

    车票信息服务, 实现ITicketService接口, 通过享元模式池化了车票信息.

    package flyweight
    
    import "sync"
    
    type tMockTicketService struct {
        mTickets map[string]ITicket
        mRWMutex *sync.RWMutex
    }
    
    func newMockTicketService() *tMockTicketService {
        return &tMockTicketService{
            make(map[string]ITicket, 0),
            new(sync.RWMutex),
        }
    }
    
    
    func (me *tMockTicketService) Get(from string, to string) ITicket {
        k := from + "-" + to
    
        me.mRWMutex.RLock()
        defer me.mRWMutex.RUnlock()
        it,ok := me.mTickets[k]
    
        if ok {
            return it
    
        } else {
            return nil
        }
    }
    
    
    func (me *tMockTicketService) Save(it ITicket) {
        k := it.From() + "-" + it.To()
    
        me.mRWMutex.Lock()
        defer me.mRWMutex.Unlock()
        me.mTickets[k] = it
    }
    
    
    var MockTicketService ITicketService = newMockTicketService()
    

    tMockTicketRemaining.go

    余票信息实体, 实现ITicketRemaining接口

    package flyweight
    
    type tMockTicketRemaining struct {
        ITicket
        iRemaining int
    }
    
    func newMockTicketRemaining(it ITicket, num int) *tMockTicketRemaining {
        return &tMockTicketRemaining{
            it, num,
        }
    }
    
    func (me *tMockTicketRemaining) Remaining() int {
        return me.iRemaining
    }
    

    tMockTicketRemainingService.go

    余票信息服务, 实现ITicketRemainingService接口. 通过ITicketService获取车票基本信息. 根据发站和到站, 查询余票信息.

    package flyweight
    
    import "sync"
    
    type tMockTicketRemainingService struct {
        mRemaining map[int]int
        mRWMutex *sync.RWMutex
    }
    
    func newMockTicketRemainingService() *tMockTicketRemainingService {
        return &tMockTicketRemainingService{
            make(map[int]int, 16),
            new(sync.RWMutex),
        }
    }
    
    
    func (me *tMockTicketRemainingService) Get(from string, to string) ITicketRemaining {
        ticket := MockTicketService.Get(from, to)
        if ticket == nil {
            return nil
        }
        r := newMockTicketRemaining(ticket, 0)
    
        me.mRWMutex.RLock()
        defer me.mRWMutex.RUnlock()
        num,ok := me.mRemaining[ticket.ID()]
    
        if ok {
            r.iRemaining = num
        }
    
        return r
    }
    
    func (me *tMockTicketRemainingService) Save(id int, num int) {
        me.mRWMutex.Lock()
        defer me.mRWMutex.Unlock()
        me.mRemaining[id] = num
    }
    
    var MockTicketRemainingService ITicketRemainingService = newMockTicketRemainingService()
    

    享元模式小结

    享元模式是对象池的一种应用.
    享元模式的优点
    (1)减少对象的创建,降低内存中对象的数量,降低系统的内存,提高效率。
    (2)减少内存之外的其他资源占用。
    享元模式的缺点
    (1)关注内、外部状态,关注线程安全问题。
    (2)使系统、程序的逻辑复杂化。
    _
    (end)

    相关文章

      网友评论

        本文标题:手撸golang 结构型设计模式 享元模式

        本文链接:https://www.haomeiwen.com/subject/mgpptltx.html