利用迪米特原则,可以实现代码的“高内聚/松耦合”,高内聚低耦合其实是一种非常重要的设计思想,能够有效地提高代码地可读性和可维护性,缩小功能改动倒置地代码改动范围。高内聚是指类本身地设计,相近地功能往往会被同时修改,放到同一个类中,修改会比较集中;松耦合是用来指导类与类之间依赖关系地设计,在代码中,类与类之间地依赖关系简单清晰。
迪米特法则,不该有直接依赖关系地类之间,不要有依赖;有依赖关系地类之间,尽量只依赖必要地接口。迪米特法则是希望减少类之间地耦合,让类越独立越好。每个类都应该少了解系统地其他部分,一旦发生变化,需要了解这一变化地类就会比较少。
引出问题
以网页搜索功能为例,NetworkTransporter 负责底层网络通信,根据请求获取数据,HtmlDownloader 通过URL获取网页,Document 表示网页文档,后续地网页内容抽取/分词/索引都是以此为处理对象。
// 网页请求
type HtmlRequest struct {}
type Html struct {}
// 负责底层网络通信,根据请求获取数据
type NetworkTransporter struct {}
// 注意1:此处依赖HtmlRequest
func (n NetworkTransporter) send(request *HtmlRequest) Html {
//....
return Html{}
}
// 通过URL获取网页
// 注意2:HtmlDownloader依赖NetworkTransporter
type HtmlDownloader struct {
transporter NetworkTransporter
}
func (h *HtmlDownloader) downloadHtml(url string) Html {
html := h.transporter.send(new(HtmlRequest))
//....
return html
}
// 表示网页文档,后续地网页内容抽取/分词/索引都是以此为处理对象
type Document struct {
html Html
url string
}
func NewDocument(url string) *Document {
return &Document{url:url}
}
// 注意3:Document依赖HtmlDownloader
func (d *Document) getDocument() {
downloader := new(HtmlDownloader)
d.html = downloader.downloadHtml(d.url)
}
以上看出三个类之间相互依赖,违反迪米特法则“不该有直接依赖关系地类之间,不要有依赖”。
迪米特法则实现
针对NetworkTransporter依赖HtmlRequest,可以修改HtmlRequest将address和content交给NetworkTransporter:
func (n NetworkTransporter) send2(address string, data []byte) Html {
//....
return Html{}
}
func (h *HtmlDownloader) downloadHtml2(url string) Html {
request := new(HtmlRequest)
html := h.transporter.send2(request.address,request.data)
//....
return html
}
针对Document依赖HtmlDownloader,可以通过简单工厂实现
type DocumentFactory struct {
downloader HtmlDownloader
}
func (d DocumentFactory) NewDocFactoty(downloader HtmlDownloader) DocumentFactory {
return DocumentFactory{
downloader:downloader,
}
}
type DocumentInf interface {
getDocument()
}
func (d DocumentFactory) createDocument(url string) DocumentInf {
html := d.downloader.downloadHtml2(url)
return &Document{
url:url,
html:html,
}
}
完整代码实现可以访问个人Github主页查看实例。
fkcs/Go-Design-Patterngithub.com