前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >设计模式: 好莱坞风格与依赖注入

设计模式: 好莱坞风格与依赖注入

作者头像
超级大猪
发布2020-04-29 16:20:27
3870
发布2020-04-29 16:20:27
举报
文章被收录于专栏:大猪的笔记

当实体 e1要调用 e2.func1的时候,一般情况下直接在e1的调用处new一个e2,并调用e2的函数。这样可能会引起一些依赖。 在设计松耦合的程序时,可以使用好莱坞风格,即将e2的函数通过e1的接口注册进e1的实体中,e1会随后在合适的时候调用。 例如:

代码语言:javascript
复制
type E1 struct {
    willCall func()
}

func (e *E1) Reg(f func()) {
    e.willCall = f // 框架在合适的时候注入e1的依赖
}

func (e *E1) Run(){
    e.willCall() // e调用的是抽象的函数,而非具体
}

下面实现一个词频统计器,参考《编程风格-好代码的逻辑》进行实现。 这个词频统计器,包含三个部分: 1. stopwords检查器,对一些助词如is, to等不进行统计 2. data处理器:将源数据转为内部的小写词表 3. 统计器: 传入word,统计它的词频,并可以打印统计结果

值得注意的是,它们之间并没有任何显示的new依赖,而是通过抽象的函数进行占位。在调用的时候,framework会进行依赖注入。 在main函数中,演示了依赖注入的整个过程。

代码语言:javascript
复制
package main

import (
    "fmt"
    "strings"
)

var originData = `The target field within a path is name for the target. This field MUST only ever be present on prefix paths in the corresponding request and response messages. This field is optional for clients. When set in the prefix in a request, GetRequest, SetRequest or SubscribeRequest, the field MUST be reflected in the prefix of the corresponding GetResponse, SetResponse or SubscribeResponse by a server. This field is used to allow a name to be associated with all the data for a given stream if requested by a client. If a client does not set this field in the prefix of a request, it MUST NOT be set in the prefix of the corresponding response messages. The value for target is tied to the context of a client RPC and not persisted or shared among multiple clients.`

var originStopwords = []string{"be", "is", "by", "and", "in", "of", "are", "to", "if", "on", "for", "the"}

type FrameWork struct {
    LoadHandlers []func()
    WorkHandlers []func()
    EndHandlers  []func()
}

func (f *FrameWork) Reg(fn func(), ttype string) {
    switch ttype {
    case "load":
        f.LoadHandlers = append(f.LoadHandlers, fn)
    case "work":
        f.WorkHandlers = append(f.WorkHandlers, fn)
    case "end":
        f.EndHandlers = append(f.EndHandlers, fn)
    }
}

func (f *FrameWork) Run() {
    for _, h := range f.LoadHandlers {
        h()
    }
    for _, h := range f.WorkHandlers {
        h()
    }
    for _, h := range f.EndHandlers {
        h()
    }
}

type StopWordFilter struct {
    stopwords []string
}

func (s *StopWordFilter) Load() {
    s.stopwords = originStopwords
}

func (s *StopWordFilter) IsStopWord(w string) bool {
    for _, tp := range s.stopwords {
        if tp == w {
            return true
        }
    }
    return false
}

type DataHandler struct {
    filters     []func(w string) bool
    wordHandler []func(w string)
    data        []string
}

func (d *DataHandler) RegFilter(f func(w string) bool) {
    d.filters = append(d.filters, f)
}
func (d *DataHandler) RegWordHandler(f func(w string)) {
    d.wordHandler = append(d.wordHandler, f)
}

func (d *DataHandler) Load() {
    tpdata := strings.Split(originData, " ")
    for _, word := range tpdata {
        word = strings.Replace(word, ".", "", -1)
        word = strings.Replace(word, "'", "", -1)
        word = strings.Replace(word, ",", "", -1)
        word = strings.Replace(word, " ", "", -1)
        word = strings.ToLower(word)
        d.data = append(d.data, word)
    }
}

func (d *DataHandler) Run() {
    isFilter := func(word string) bool {
        for _, filter := range d.filters {
            if filter(word) == true {
                return true
            }
        }
        return false
    }
    for _, word := range d.data {
        if isFilter(word) == false {
            for _, h := range d.wordHandler {
                h(word)
            }
        }
    }
}

type WordsCounter struct {
    counts map[string]int
}

func (w *WordsCounter) Load() {
    w.counts = make(map[string]int)

}

func (w *WordsCounter) Count(word string) {
    _, ok := w.counts[word]
    if ok {
        w.counts[word]++
    } else {
        w.counts[word] = 1
    }
}

func (w *WordsCounter) PrintAll() {
    for key := range w.counts {
        fmt.Printf("word:%v, count:%v\n", key, w.counts[key])
    }
}

func main() {
    framework := new(FrameWork)
    dataHandler := new(DataHandler)
    stopwordsFilter := new(StopWordFilter)
    counter := new(WordsCounter)

    framework.Reg(dataHandler.Load, "load")
    framework.Reg(stopwordsFilter.Load, "load")
    framework.Reg(counter.Load, "load")

    dataHandler.RegFilter(stopwordsFilter.IsStopWord)
    dataHandler.RegWordHandler(counter.Count)

    framework.Reg(dataHandler.Run, "work")
    framework.Reg(counter.PrintAll, "end")

    framework.Run()
}
本文参与 腾讯云自媒体同步曝光计划,分享自作者个人站点/博客。
原始发表:2020-04-28 ,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 作者个人站点/博客 前往查看

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档