【原创+探讨+分享】关于有继承关系的抽象类实现方式的初步探讨
现状
两个或以上的有继承关系的抽象类设计与实现
网上几乎找不到相关的设计经验和技巧
可能这种场景对大家来说会相对比较少
但是我相信客观还是存在的
尤其是在写框架或组件的时候
想把那种与具体业务和架构无关的可以确定的业务逻辑尽量封装在抽象层
以减少和简化扩展时的代码量和重复代码的出现
如果哪位有看见类似的探讨议题 请告知一下 谢谢
下面进入正题 把自己对该场景的一些思路和大家分享一下
一、问题的提出
如果有两个继承关系的抽象类,如下:
public abstract class ListControlBase { public abstract object ListShowControl { get; } public abstract void DataBind(); } public abstract class ListSortControlBase : ListControlBase { public abstract object Order { get; } }
面对上面的2个抽象类
一般大家都会这样去实现
public class ListControl : Core.ListControlBase { public override object ListShowControl { get { throw new NotImplementedException(); } } public override void DataBind() { throw new NotImplementedException(); } } public class ListSortControl : ListSortControlBase { public override object Order { get { throw new NotImplementedException(); } } public override object ListShowControl { get { throw new NotImplementedException(); } } public override void DataBind() { throw new NotImplementedException(); } }
这样的实现方式固然是没有错
但是仔细观察 就会发现
public override object ListShowControl { get { throw new NotImplementedException(); } }
这个属性(用来绑定数据的List控件)代码实现了2次
而且代码可能几乎是一摸一样的
尽管2个抽象类的DataBind方法
实现起来的代码可能不一样
但是因为有重复代码
追求完美的人肯定是不能接受这样的设计
这样的实现不符合代码重用原则
这还只是2层的继承关系
如果继承层次一多
大量的重复代码大家可想而知
这是非常糟糕的设计
大家一定在想:
如果有类的双重机制就好办了
ListSortControl : ListSortControlBase, ListControl
C++确实可以办得到,但是这样对于大多是语言来说是办不到的,因此C++的解决方案不具有一般性。
二、问题的改进
那么用什么方式会比较好呢?
来修改下继承的抽象类,如下:
public abstract class ListSortControlBase : ListControlBase { public abstract ListControlBase ListControl { get; } public abstract object Order { get; } public override object ListShowControl { get { return ListControl.ListShowControl; } } }
这个改动大致的思路是:
在一个继承的抽象类里面,写一个父抽象类的引用属性
这时候在实现的时候,可以指代一个父抽象类的子类的某个直接具体实现
然后就可以用父抽象类的子类的业务逻辑 确定本类实现过程中的某些通用业务逻辑
而这些业务逻辑,在实现两个时候,代码是一摸一样的。
其实泛泛想下:
这也是C#或其他不支持类的多重继承的语言当中,实现多重继承的一个非主流解决方案。
实现方式如下:
public class ListSortControl : ListSortControlBase { public override object Order { get { throw new NotImplementedException(); } } public override void DataBind() { throw new NotImplementedException(); } ListControlBase _listControl = new ListControl(); public override ListControlBase ListControl { get { return _listControl; } } }
这种方式的继承,不仅可以实现抽象类之前的继承关系
还可以大范围复用父类某个实现的共同业务代码
ListSortControlBase对子类隐藏了属性ListShowControl的实现
改用ListControl的某个ListShowControl的业务实现
极大地简化了实现子抽象类ListSortControlBase的代码
达到复用父抽象类ListControlBase的某个实现的目的
三、新的问题
虽然改进的子抽象类可以最大限度复用父抽象类的某些实现代码
但是这对于父抽象类某个实现来说 可能并不是一个简单地用new来创建ListControl
可能ListControBase有复杂的初始化过程,否则ListControBase的某些属性或业务代码是不可用的
这样就把ListControBase复杂的初始化过程 嫁接给了ListSortControlBase
这个问题是始终存在的 根本不可以避免
但是如果设计得体 理顺ListControBase的初始化过程 那么也还是可以顺利完成ListSortControlBase的某些共同业务在抽象层面的封装
总的来说 虽然复用了ListControl业务实现代码
但是可能增加了ListSortControlBase复杂性
需要考虑的问题有时候可能会有很多
四、总结
1、如果类的复杂度不高,可以使用改进的方式实现2个抽象类;
2、如果类的实现涉及复杂的初始化过程, 为了避免因为初始化的问题,从而导致一些隐藏bug,用一般的实现方法 也不失为一种不完美的可行方案;
3、如果有其他更好的设计和实现方案 请不吝告知下 不甚感激。