里氏替换&开放关闭
Posted by 付辉 on Thursday, June 6, 2019 共613字里氏替换
Let Φ(x) be a property provable about objects x of type T. Then Φ(y) should be true for objects y of type S where S is a subtype of T
本质上就是类设计中的继承,它强调类所实现的行为。参数的类型指定为基类,而实际传参的时候使用具体的子类。每次扩展新的行为,都通过创建一个新的子类来实现。在Go的设计中,继承是通过接口类型来实现的。
开放关闭
Software entities (classes, modules, function, etc) should be open for extension, but closed for modification.
A class is closed, since it may be complied, stored in a library, baselined and used by client classes. but it alse be open, since any new class may use it as parent, adding new features. when a descendant class is defined, there is no need to change the original or to disturb its clients.
原则上支持扩展,禁止修改,感觉是里氏替代的扩展。基类或者接口是对修改关闭的,而具体的实现是对修改开放的。
例子
参考代码:github.com/gin-gonic/gin/binding
声明Binding
接口来当作基类,Binding
对修改关闭。
// Binding describes the interface which needs to be implemented for binding the
// data present in the request such as JSON request body, query parameters or
// the form POST.
type Binding interface {
Name() string
Bind(*http.Request, interface{}) error
}
工厂模式创建子类,每个子类实现处理不同的请求类型。如果扩展新的contentType的话,创建新的子类对修改开放。
// Default returns the appropriate Binding instance based on the HTTP method
// and the content type.
func Default(method, contentType string) Binding {
if method == "GET" {
return Form
}
switch contentType {
case MIMEJSON:
return JSON
case MIMEXML, MIMEXML2:
return XML
case MIMEPROTOBUF:
return ProtoBuf
case MIMEMSGPACK, MIMEMSGPACK2:
return MsgPack
default: //case MIMEPOSTForm, MIMEMultipartPOSTForm:
return Form
}
}
里氏替代原则实现处理:
// MustBindWith binds the passed struct pointer using the specified binding engine.
// It will abort the request with HTTP 400 if any error ocurrs.
// See the binding package.
func (c *Context) MustBindWith(obj interface{}, b binding.Binding) (err error) {
if err = c.ShouldBindWith(obj, b); err != nil {
c.AbortWithError(http.StatusBadRequest, err).SetType(ErrorTypeBind)
}
return
}
总结
通过抽象基类来约束行为,通过实现基类来扩展具体的实现。最终达到修改对现有项目影响最小的目的。
参考文章: