设计模式:参与者风格
时间:2022-07-25
本文章向大家介绍设计模式:参与者风格,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。
概述
参与者风格将问题分解为问题域相关的对象,每个对象中存在一个队列,并且暴露唯一的send接口用于给队列添加消息。对象轮循队列,并根据取出的不同消息执行不同的操作。
此风格适用于大型分布式系统中。每个组件不共享内存,使用消息进行功能的交互。
模式
下面实现一个词频统计器,即统计一段文章中top25的词频。 主要结构如下: WordFrequencyController 管理者,它将文章切成词,然后逐个发送给StopWordManager
StopWordManager 包含一个停止词表。用来过滤停止词,如文章中的is, are等词为停止词,不进行词汇统计。如果接收到的词不在停止词中,则发送给词频统计器
WordFrequencyManager 包含词频表,接收到的词进行词频增加。并可以接收print命令。
大概的流程是:
WordFrequencyController --send--> StopWordManager --send--> WordFrequencyManager
每个结构体对象都运行在不同的线程中,使用暴露的Send方法进行通讯。
具体代码
package main
import (
"fmt"
"strings"
"time"
)
func main() {
manager := new(WordFrequencyManager)
manager.queue = make(chan []interface{})
manager.wordMap = make(map[string]int)
go manager.Run()
stopWordManager := new(StopWordManager)
stopWordManager.queue = make(chan []interface{})
stopWordManager.manager = manager
stopWordManager.stopWords = []string{"be", "is", "by", "and", "in", "of", "are", "to", "if", "on", "for", "the"}
go stopWordManager.Run()
controller := new(WordFrequencyController)
controller.queue = make(chan []interface{})
controller.manager = stopWordManager
go controller.Run()
controller.Send([]interface{}{"send_words", originData})
time.Sleep(time.Millisecond * 300)
manager.Send([]interface{}{"print"})
time.Sleep(time.Millisecond * 300)
}
type WordFrequencyController struct {
queue chan []interface{}
manager *StopWordManager
}
func (w *WordFrequencyController) Send(msg []interface{}) {
w.queue <- msg
}
func (w *WordFrequencyController) Run() {
for msg := range w.queue {
ttype := msg[0]
wordsStr := msg[1].(string)
if ttype == "send_words" {
words := w.split(wordsStr)
for _, word := range words {
w.manager.Send([]interface{}{"filter", word})
}
}
}
}
func (w *WordFrequencyController) split(words string) []string {
tpdata := strings.Split(words, " ")
ret := make([]string, 0)
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)
ret = append(ret, word)
}
return ret
}
type WordFrequencyManager struct {
queue chan []interface{}
wordMap map[string]int
}
func (w *WordFrequencyManager) Send(msg []interface{}) {
w.queue <- msg
}
func (w *WordFrequencyManager) Run() {
for msg := range w.queue {
ttype := msg[0]
if ttype == "word" {
word := msg[1].(string)
v, ok := w.wordMap[word]
if ok {
w.wordMap[word] = v + 1
} else {
w.wordMap[word] = 1
}
} else if ttype == "print" {
fmt.Println(w.wordMap)
}
}
}
type StopWordManager struct {
queue chan []interface{}
stopWords []string
manager *WordFrequencyManager
}
func (s *StopWordManager) Send(msg []interface{}) {
s.queue <- msg
}
func (s *StopWordManager) Run() {
for msg := range s.queue {
ttype := msg[0].(string)
word := msg[1].(string)
if ttype == "filter" {
if !StrIn(word, s.stopWords) {
s.manager.Send([]interface{}{"word", word})
}
}
}
}
func StrIn(w string, l []string) bool {
for _, item := range l {
if w == item {
return true
}
}
return false
}
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.`
- 理解闭包 js回收机制
- java 解析 XML实例
- Java 线程内异常处理
- Raphael path 拖动实现
- 黑猿大叔-译文 | TensorFlow实现Batch Normalization
- Java后端WebSocket的Tomcat实现
- jwplayer 隐藏属性方法记载
- TensorFlow从0到1丨开篇:Hello TensorFlow !
- JS原型继承和类式继承
- 在Servlet的init方法中创建线程
- TensorFlow从0到1丨第2篇:TensorFlow核心编程
- AngularJS中的按需加载ocLazyLoad
- AngularJS driective 封装 自动滚动插件
- java类过滤器,防止页面SQL注入
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Linux下使用 github+hexo 搭建个人博客07-next主题接入搜索和站点管理
- Linux curl 命令详解
- Linux curl 常用示例
- Linux curl 表单登录或提交与cookie使用
- Rsync 服务部署与参数详解
- Linux 查看磁盘IO并找出占用IO读写很高的进程
- Linux tcpdump 命令详解与示例
- 手动搭建Hadoop分布式集群
- Ansible-安装配置
- React-Redux 100行代码简易版探究原理。
- Ansible-免密登录与主机清单Inventory
- 安装Ambari和HDP
- React中引入Vue3的@vue/reactivity 实现响应式状态管理
- Ansible Ad-Hoc与常用模块
- Ansible Playbook 初识