ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

golang-设计模式-接口隔离原则-学习笔记

2022-03-19 17:59:01  阅读:201  来源: 互联网

标签:string RedisConfig 接口隔离 golang host func 设计模式 config port


​【1】基本理论    
        OOP 中的接口,也可以理解为面向对象编程语言中的接口语法。接口的设计要尽量单一,不要让接口的实现类和调用者,依赖不需要的接口函数。

【2】功能描述
        假设我们的项目中用到了三个外部系统:Redis、MySQL、Kafka。每个系统都对应一系列配置信息,比如地址、端口、访问超时时间等。为了在内存中存储这些配置信息,供项目中的其他模块来使用,我们分别设计实现了三个 Configuration 类:RedisConfig、MysqlConfig、KafkaConfig。

    现在我们有如下两个功能需求:
    1.支持 Redis 和 Kafka 配置信息的热更新。
    但是,因为某些原因,我们并不希望对 MySQL 的配置信息进行热更新。

    2.我们希望能有一种更加方便的配置信息查看方式。
    比如在项目中开发一个内嵌的 SimpleHttpServer,输出项目的配置信息到一个固定的HTTP地  址,比如:http://127.0.0.1:9200/config/redis。我们只需要在浏览器中输入这个地址,就可以显示出系统的配置信息。

     不过,出于某些原因,我们只想暴露 MySQL 和 Redis 的配置信息,不想暴露 Kafka 的配置信息。
 
 【3】设计思路
         我们设计了两个功能非常单一的接口:Updater 和 Viewer。

         为了实现这样一个功能需求,我们设计实现了一个 ScheduledUpdater 类,以固定时间间隔(interVal)调用 RedisConfig、KafkaConfig 的 Update() 方法更新配置信息。ScheduledUpdater 只依赖 Updater 这个跟热更新相关的接口,不需要被强迫去依赖不需要的 Viewer 接口,满足接口隔离原则。

        同理,SimpleHttpSvr 只依赖跟查看信息相关的 Viewer 接口,不依赖不需要的 Updater 接口,也满足接口隔离原则。

【4】Demo实战

(说明:热更新和浏览器输出代码 都通过输出语句和注释说明的描述简单代替。)

package main

import (
	"fmt"
	"time"
)

//更新接口
type Updater interface {
	Update()
}

//查看接口
type Viewer interface {
	OutputInPlainText() string
	OutPut() map[string]string
}

//Redis 配置
type RedisConfig struct {
	host string
	port string
	auth string
}

func NewRedisConfig(host string, port string, auth string) *RedisConfig {
	return &RedisConfig{
		host: host,
		port: port,
		auth: auth,
	}
}

func (config *RedisConfig) Update() {
	fmt.Println("RedisConfig::update(), reload data from private redis config")
	//config.host,config.port,config.auth = readfile congfig...
	fmt.Printf("update config(%s,%s,%s) succ\n", config.host, config.port, config.auth)
}

func (config *RedisConfig) OutputInPlainText() string {
	str := "RedisConfig::outputInPlainText"
	fmt.Println(str)
	return str
}

func (config *RedisConfig) OutPut() map[string]string {
	mp := make(map[string]string)
	mp[config.host] = config.port
	return mp
}

//Kafka配置
type KafkaConfig struct {
	path  string
	topic string
}

func NewKafkaConfig(path string, topic string) *KafkaConfig {
	return &KafkaConfig{
		path:  path,
		topic: topic,
	}
}

func (config *KafkaConfig) Update() {
	fmt.Println("KafkaConfig::update(), reload data from private redis config")
	//config.path,config.topic = readfile congfig...
	fmt.Printf("update config(%s,%s) succ\n", config.path, config.topic)
}

//MySQL配置
type MySqlConfig struct {
	host     string
	port     string
	passWord string
	dbName   string
}

func NewMySqlConfig(host string, port string, passWord string, dbName string) *MySqlConfig {
	return &MySqlConfig{
		host:     host,
		port:     port,
		passWord: passWord,
		dbName:   dbName,
	}
}

func (config *MySqlConfig) OutputInPlainText() string {
	str := "MySqlConfig::outputInPlainText"
	fmt.Println(str)
	return str
}

func (config *MySqlConfig) OutPut() map[string]string {
	mp := make(map[string]string)
	mp[config.dbName] = config.host + "_" + config.passWord
	return mp
}

//定时更新器
type ScheduledUpdater struct {
	interVal int
	updater  Updater
}

func NewScheduledUpdater(interval int, updater Updater) *ScheduledUpdater {
	return &ScheduledUpdater{
		interVal: interval,
		updater:  updater,
	}
}

func (scheduledUpdater *ScheduledUpdater) Run() {
	ticker := time.NewTicker(time.Duration(scheduledUpdater.interVal) * time.Second)
	go func() {
		for t := range ticker.C {
			fmt.Printf("Tick at %v\n", t)
			scheduledUpdater.updater.Update()
		}
	}()
}

//简单HttpServer
type SimpleHttpSvr struct {
	host      string
	port      int
	mpViewers map[string][]Viewer
}

func NewSimpleHttpSvr(host string, port int) *SimpleHttpSvr {
	return &SimpleHttpSvr{
		host:      host,
		port:      port,
		mpViewers: make(map[string][]Viewer),
	}
}

func (svr *SimpleHttpSvr) AddViewer(urlDirectory string, viewer Viewer) {
	svr.mpViewers[urlDirectory] = append(svr.mpViewers[urlDirectory], viewer)
}

func (svr *SimpleHttpSvr) Run() {
	for dir, viewers := range svr.mpViewers {
		fmt.Printf("urlDir:%s\n", dir)
		for _, view := range viewers {
			view.OutputInPlainText()
			fmt.Printf("Ouput:%v\n", view.OutPut())
		}
	}
}

func main() {
	redisConfig := NewRedisConfig("192.168.1.1", "6379", "redis_123")
	kafkaConfig := NewKafkaConfig("Kafka_Test:9092", "OrderState")
	mysqlConfig1 := NewMySqlConfig("192.168.1.2", "6379", "pwd001", "price_db")
	mysqlConfig2 := NewMySqlConfig("192.168.1.3", "6379", "pwd002", "order_db")

	redisConfigUpdater := NewScheduledUpdater(30, redisConfig)
	redisConfigUpdater.Run()
	kafaConfigUpdater := NewScheduledUpdater(15, kafkaConfig)
	kafaConfigUpdater.Run()

	SimpleHttpSvr := NewSimpleHttpSvr("127.0.0.1", 9200)
	SimpleHttpSvr.AddViewer("/config/redis", redisConfig)
	SimpleHttpSvr.AddViewer("/config/mysql", mysqlConfig1)
	SimpleHttpSvr.AddViewer("/config/mysql", mysqlConfig2)
	SimpleHttpSvr.Run()

	select {}
}

运行结果:
//模拟 SimpleHttpSvr 展示 RedisConfig和 MySqlConfig

urlDir:/config/redis
RedisConfig::outputInPlainText
Ouput:map[192.168.1.1:6379]
urlDir:/config/mysql
MySqlConfig::outputInPlainText
Ouput:map[price_db:192.168.1.2_pwd001]
MySqlConfig::outputInPlainText
Ouput:map[order_db:192.168.1.3_pwd002]

//模拟 定时热更新 KafkaConfig和RedisConfig

Tick at 2022-03-19 17:30:27.022323599 +0800 CST m=+15.012814195
KafkaConfig::update(), reload data from private redis config
update config(Kafka_Test:9092,OrderState) succ
Tick at 2022-03-19 17:30:42.024135251 +0800 CST m=+30.014625841
KafkaConfig::update(), reload data from private redis config
update config(Kafka_Test:9092,OrderState) succ
Tick at 2022-03-19 17:30:42.024132902 +0800 CST m=+30.014623512
RedisConfig::update(), reload data from private redis config
update config(192.168.1.1,6379,redis_123) succ

标签:string,RedisConfig,接口隔离,golang,host,func,设计模式,config,port
来源: https://blog.csdn.net/u012309042/article/details/123598673

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有