請(qǐng)描述什么是依賴(lài)倒置原則,為什么有時(shí)候依賴(lài)倒置原則又被稱(chēng)為好萊塢原則憾股?
依賴(lài)倒置原則是一種解耦模塊間關(guān)系的方法鹿蜀,它要求上層模塊不能依賴(lài)于底層模塊,他們應(yīng)該共同依賴(lài)于一個(gè)抽象服球;抽象不能依賴(lài)于實(shí)現(xiàn)茴恰,實(shí)現(xiàn)應(yīng)該依賴(lài)于抽象。
在底層實(shí)現(xiàn)發(fā)生變化或者引入新的底層實(shí)現(xiàn)時(shí)斩熊,通過(guò)共同依賴(lài)于抽象往枣,可以使得改動(dòng)對(duì)上層模塊的影響最小化。
好萊塢原則通俗講是你不要調(diào)用我粉渠,讓我來(lái)調(diào)用你分冈。這個(gè)關(guān)系的反轉(zhuǎn)和依賴(lài)倒置的核心思想是一致的,好萊塢所講的可以理解為框架會(huì)定義一系列的接口霸株,各種基于框架開(kāi)發(fā)的應(yīng)用程序只需要實(shí)現(xiàn)這些接口雕沉,框架在啟動(dòng)之后它會(huì)來(lái)調(diào)用應(yīng)用程序?qū)崿F(xiàn)的這些接口,讓程序運(yùn)行起來(lái)去件。請(qǐng)描述一個(gè)你熟悉的框架坡椒,是如何實(shí)現(xiàn)依賴(lài)倒置原則的饺著。
最近在做一個(gè)對(duì)圖片做離線(xiàn)處理的pipeline系統(tǒng),主要基于https://github.com/digitalocean/firebolt這個(gè)框架進(jìn)行的開(kāi)發(fā)肠牲。
此框架定義了consumer中接收消息的source node的接口,以及pipeline處理中算子node的接口靴跛,作為使用框架的開(kāi)發(fā)人員只需要按接口要求把處理邏輯封裝在這些接口方法中缀雳,然后在程序啟動(dòng)前,將實(shí)現(xiàn)注冊(cè)到firebolt框架梢睛,然后啟動(dòng)firebolt肥印,框架就會(huì)按照開(kāi)發(fā)者定義的處理流程配置文件來(lái)按序執(zhí)行pipeline處理。
source node負(fù)責(zé)接收消息
type Source interface {
Setup(config map[string]string, recordsch chan []byte) error
Start() error
Shutdown() error
Receive(msg fbcontext.Message) error
}
sync node 負(fù)責(zé)處理業(yè)務(wù)邏輯的算子
type SyncNode interface {
Setup(config map[string]string) error
Process(event *firebolt.Event) (*firebolt.Event, error)
Shutdown() error
Receive(msg fbcontext.Message) error
}
config file 用來(lái)定義這個(gè)pipeline處理流程
source: # one and only one source is required
name: kafkaconsumer
params:
brokers: ${KAFKA_BROKERS} # environment variables are supported
consumergroup: testapp
topic: logs-all
buffersize: 1000 # sources do not normally need buffering; this value is a pass-thru to the underlying kafka consumer
nodes:
- name: firstnode
workers: 1 # each node can be configured to run any number of workers (goroutines), the default is 1
buffersize: 100 # each node has a buffered input channel for the data that is ready to be processed, default size is 1
params: # params are passed as a map to the node's Setup() during initialization
param1.1: value1.1
param1.2: value1.2
children: # a node may have many children, the events returned by the node are passed to all child node's input channels
- name: secondnode
error_handler: # errors returned by 'secondnode' will be passed to this error handler
name: errorkafkaproducer # we provide built-in 'errorkafkaproducer' that writes JSON error reports to a Kafka topic
buffersize: 100
discard_on_full_buffer: true # if the buffer is full discard messages to avoid sending backpressure downstream for a low priority function
children:
- name: thirdnode
id: third-node-id # you can use the same node type in your hierarchy twice, but its id (defaults to name) must be unique
workers: 3
buffersize: 300
params:
param3.1: value3.1
param3.2: value3.2
主程序通過(guò)node.GetRegistry().RegisterNodeType注冊(cè)已實(shí)現(xiàn)的node绝葡,并啟動(dòng)executor
// first register any firebolt source or node types that are not built-in
node.GetRegistry().RegisterNodeType("jsonconverter", func() node.Node {
return &jsonconverter.JsonConverter{}
}, reflect.TypeOf(([]byte)(nil)), reflect.TypeOf(""))
// start the executor running - it will build the source and nodes that process the stream
ex, err := executor.New(configFile)
if err != nil {
fmt.Printf("failed to initialize firebolt for config file %s: %v\n", configFile, err)
os.Exit(1)
}
ex.Execute() // the call to Execute will block while the app runs
由于golang沒(méi)有Java強(qiáng)大的泛型和annotation深碱,因此需要在主程序中顯示的注冊(cè)各種實(shí)現(xiàn)好的node
- 請(qǐng)用接口隔離原則優(yōu)化 Cache 類(lèi)的設(shè)計(jì),畫(huà)出優(yōu)化后的類(lèi)圖
type CacheConfig interface {
}
type CacheStorage interface {
Get(key string) (interface{}, error)
Set(key, value string) error
Delete(key string) error
}
type CacheHandler interface {
ReBuild(conf CacheConfig) (CacheStorage, error)
}
type CacheProxy struct {
ActiveCache CacheStorage
CacheHandler
}
應(yīng)用程序中使用時(shí)藏畅,使用方法為
var (
err error
activeCache CacheStorage
)
activeCache, err = NewCacheProxy(cacheConf)
遠(yuǎn)程系統(tǒng)調(diào)用時(shí)敷硅,使用方法為
var (
err error
var cacheHandler CacheHandler
)
cacheHandler, err = NewCacheProxy(cacheConf)