这是在OOD中会经常遇到的问题,比较典型。
一句话简单来说的话,就是目前你的领域模型并不完整,不支持你做出最合适的选择。这两种接口设计都有各自的优劣势,但是在目前所掌握的需求中来看并不能看出哪一种更加优秀。
两种设计的根本性的差别还不在于后一种需要写重复的代码,因为你可以用一个公共的基类型(如Pickable或者PickableBase)来解决掉所有的重复代码。
所以后一种模式的根本性的区别在于Packer无法约束OnPick的逻辑。
如果Packer的Pick方法不接受IPickable类型而是强类型的Pickable或者PickableBase,里面的OnPick的逻辑就会被强约束(如果不是virtual的)。这种设计和第一种就没有什么本质上的区别。
所以两种设计的根本性区别在于Packer是否需要对Pick动作进行强约束。开放当然是好,但是我们必须在开放和封闭之间做出权衡和取舍。一个简单的说法就是:无所不能的机器无所不能。意思是:什么都能做的机器其实什么都做不了。
没有任何约束的Packer只剩下名字,只有语义的规约。但是约束到何种程度,到底哪些东西必须被约束,哪些可能性不可能出现,这需要对需求的深刻理解和彻底分析。
在需求不能明确所有细节之前,没有办法去讨论哪一种设计更好。但是我们可以不断重构程序来适配渐进明细的需求。
但是从重构的角度来说,第一种方式的做法显然不利于重构。像上面所说的,使用具体的类型Pickable的非虚方法来约束在后面的重构中更加简单。可以看一下这段代码:
public class Packer { public Pick( Pickable item ) { item.OnPick( this );//强约束一定调用的是Pickable的OnPick方法,且这个方法不可被重写。 } } public class Pickable { public OnPick( Packer ) { //... } }
这种写法和第一种写法本质上是一样的。不要认为两个类型就是两个负责人,两个类型可以是一个负责人,一个模块。当然,你想把代码写到哪个类型都是可以的,因为你还可以这样:
public class Packer { public Pick( Pickable item ) { item.OnPick( this );//强约束一定调用的是Pickable的OnPick方法,且这个方法不可被重写。 } internal Add( Pickable item ) { //... } } public class Pickable { public OnPick( Packer packer ) { packer.Add( this ); } }
所以,代码写在哪个类型无关紧要,关键的在于接口和约束。
回到问题,强约束和弱约束两种模式到底哪种好?
不知道
事实上有两种重构的风格:
一种是由强到弱,这种模式假定所有没有列出的需求暂时都不存在,追加的需求有追加的资源投入。所以所有的约束按照强约束设计,减少扩展和变化的空间,增强系统可靠性。
一种是由弱到强,这种模式假定程序还没做完需求就会发生变化,一切皆有可能。所以所有的约束按照弱约束设计,增加扩展和变化的空间,但是系统的可靠性会降低。
但是这只是两个极端,任何实际的项目都是在这两种模式之间做权衡和取舍。
对于核心关键的功能,我们要减少扩展和变化的空间,可靠性第一位。例如充值,消费,余额等。
对于需求不明确的功能,我们要预留扩展和变化的空间,在需求稳定之后,我们再进行强约束改造。
饭圈不是瘟疫。瘟疫的可怕在于传染性,饭圈没有传染性,只有破坏性。硬要比喻的话可以称为蝗虫。
辱骂饭圈不是政治正确。「政治正确」的意思是用迎合主流价值观的方式表达同一个事物或观点,以。例如称保姆为「家政」,称裁员为「业务重组」,称饭圈为「支持者」等。
「理智的粉丝」是一个伪概念。有理智的人不会无条件无原则地支持和维护没有才华只有包装的所谓演员,或者现实中甚至不存在的虚拟角色什么的。既然你坚持自己是粉丝,就说明你不具备起码的理智。