golang 架构设计原则 合成复用原则

您所在的位置:网站首页 java合成复用原则代码 golang 架构设计原则 合成复用原则

golang 架构设计原则 合成复用原则

2023-11-19 13:21| 来源: 网络整理| 查看: 265

golang 架构设计原则 合成复用原则 ioly · · 360 次点击 · · 开始浏览     这是一个创建于 的文章,其中的信息可能已经有所发展或是发生改变。 第一次,站长亲自招 Gopher 了>>> golang 架构设计原则 合成复用原则 缘起

最近复习设计模式 拜读谭勇德的 该书以java语言演绎了常见设计模式 本系列笔记拟采用golang练习之

合成复用原则 合成复用原则(Composite/Aggregate Reuse Principle, CARP)指尽量使用对象组合(has-a)或对象聚合(contanis-a)的方式实现代码复用,而不是用继承关系达到代码复用的目的。合成复用原则可以使系统更加灵活,降低类与类之间的耦合度,一个类的变化对其他类造成的影响相对较小。 继承,又被称为白箱复用,相当于把所有实现细节暴露给子类。组合/聚合又被称为黑箱复用,对类以外的对象是无法获取实现细节的。

_

场景 某订单业务系统, 需要连接数据库对产品信息进行CRUD操作 不好的设计: 定义DBConnection类, 实现对数据库的连接和SQL执行 定义ProductDAO类, 继承DBConnection类, 并封装对产品资料的增删改查 问题: ProductDAO对DBConnection的继承仅仅是为了代码复用, 不符合合成复用原则 更好的设计: 定义IDBConnection接口 定义MysqlConnection类, 实现对mysql数据库的连接和SQL执行 定义ProductDAO类, 通过Setter方法注入IDBConnection实例

_

Product.go

产品实体类

package composite_reuse type Product struct { ID int Name string Price float64 } func NewProduct(id int, name string, price float64) *Product { return &Product{ id, name, price, } }

_

BadDBConnection.go

BadDBConnection用于连接数据库并执行SQL语句

package composite_reuse import "fmt" type BadDBConnection struct { sURL string sUID string sPWD string } func NewBadDBConnection(url string, uid string, pwd string) *BadDBConnection { return &BadDBConnection{ url, uid, pwd, } } func (me *BadDBConnection) Execute(sql string, args... interface{}) (error, int) { fmt.Printf("BadDBConnection.Execute, sql=%v, args=%v\n", sql, args) return nil,0 } BadProductDAO.go

不好的设计. 直接从BadDBConnection继承, 以获取访问数据库的能力. 继承仅仅是为了代码复用, 而不是概念复用, 因此违反了合成复用原则.

package composite_reuse type BadProductDAO struct { BadDBConnection } func NewBadProductDAO(url string, uid string, pwd string) *BadProductDAO { return &BadProductDAO{ *NewBadDBConnection(url, uid, pwd), } } func (me *BadProductDAO) Insert(it *Product) (error, int) { return me.Execute("insert into product(id,name,price) values(?, ?, ?)", it.ID, it.Name, it.Price) } func (me *BadProductDAO) Update(it *Product) (error, int) { return me.Execute("update product set name=? price=? where id=?", it.Name, it.Price, it.ID) } func (me *BadProductDAO) Delete(id int) (error, int) { return me.Execute("delete from product where id=?", id) } IGoodDBConnection.go

更好的设计, 将数据库连接抽象为接口, 以支持多种数据库

package composite_reuse type IGoodDBConnection interface { Execute(sql string, args... interface{}) (error, int) } GoodMysqlConnection.go

更好的设计, GoodMysqlConnection封装MYSQL数据库方言, 实现IGoodDBConnection接口

package composite_reuse import "fmt" type GoodMysqlConnection struct { sURL string sUID string sPWD string } func NewGoodMysqlConnection(url string, uid string, pwd string) IGoodDBConnection { return &GoodMysqlConnection{ url, uid, pwd, } } func (me *GoodMysqlConnection) Execute(sql string, args... interface{}) (error, int) { fmt.Printf("GoodMysqlConnection.Execute, sql=%v, args=%v\n", sql, args) return nil, 0 } GoodProductDAO.go

更好的设计, 通过Setter方法注入数据库方言实例(遵循了合成复用原则), 实现产品的CRUD

package composite_reuse type GoodProductDAO struct { mDBConnection IGoodDBConnection } func NewGoodProductDAO() *GoodProductDAO { return &GoodProductDAO{} } func (me *GoodProductDAO) SetDBConnection(it IGoodDBConnection) { me.mDBConnection = it } func (me *GoodProductDAO) Insert(it *Product) (error, int) { return me.mDBConnection.Execute("insert into product(id,name,price) values(?, ?, ?)", it.ID, it.Name, it.Price) } func (me *GoodProductDAO) Update(it *Product) (error, int) { return me.mDBConnection.Execute("update product set name=? price=? where id=?", it.Name, it.Price, it.ID) } func (me *GoodProductDAO) Delete(id int) (error, int) { return me.mDBConnection.Execute("delete from product where id=?", id) } composite_reuse_test.go

单元测试

package main import "testing" import (carp "learning/gooop/principles/composite_reuse") func Test_CARP(t *testing.T) { p := carp.NewProduct(1, "手机", 1000) fnCallAndLog := func(fn func() (error, int)) { e,rows := fn() if e != nil { t.Errorf("error = %s", e.Error()) } else { t.Logf("affected rows = %v", rows) } } // begin testing bad ////////////////////////////////////////////////////////////// bd := carp.NewBadProductDAO("database connection url", "sa", "123") fnCallAndLog(func() (error, int) { return bd.Insert(p) }) fnCallAndLog(func() (error, int) { return bd.Update(p) }) fnCallAndLog(func() (error, int) { return bd.Delete(p.ID) }) // end testing bad ////////////////////////////////////////////////////////////// // begin testing good ////////////////////////////////////////////////////////////// con := carp.NewGoodMysqlConnection("database connection url", "sa", "123") gd := carp.NewGoodProductDAO() gd.SetDBConnection(con) fnCallAndLog(func() (error, int) { return gd.Insert(p) }) fnCallAndLog(func() (error, int) { return gd.Update(p) }) fnCallAndLog(func() (error, int) { return gd.Delete(p.ID) }) // end testing good ////////////////////////////////////////////////////////////// } 测试输出 $ go test -v composite_reuse_test.go === RUN Test_CARP BadDBConnection.Execute, sql=insert into product(id,name,price) values(?, ?, ?), args=[1 手机 1000] composite_reuse_test.go:13: affected rows = 0 BadDBConnection.Execute, sql=update product set name=? price=? where id=?, args=[手机 1000 1] composite_reuse_test.go:13: affected rows = 0 BadDBConnection.Execute, sql=delete from product where id=?, args=[1] composite_reuse_test.go:13: affected rows = 0 GoodMysqlConnection.Execute, sql=insert into product(id,name,price) values(?, ?, ?), args=[1 手机 1000] composite_reuse_test.go:13: affected rows = 0 GoodMysqlConnection.Execute, sql=update product set name=? price=? where id=?, args=[手机 1000 1] composite_reuse_test.go:13: affected rows = 0 GoodMysqlConnection.Execute, sql=delete from product where id=?, args=[1] composite_reuse_test.go:13: affected rows = 0 --- PASS: Test_CARP (0.00s) PASS ok command-line-arguments 0.004s

有疑问加站长微信联系(非本文作者)

本文来自:简书

感谢作者:ioly

查看原文:golang 架构设计原则 合成复用原则

入群交流(和以上内容无关):加入Go大咖交流群,或添加微信:liuxiaoyan-s 备注:入群;或加QQ群:692541889

关注微信 360 次点击   加入收藏 微博 赞


【本文地址】


今日新闻


推荐新闻


CopyRight 2018-2019 办公设备维修网 版权所有 豫ICP备15022753号-3