我有一个问题需要了解如何解决并行继承问题。
Fowler定义并行继承如下[1,第68页]:
并行继承层次结构实际上是霰弹枪的一个特例 手术。在这种情况下,每次创建一个类的子类时, 你还必须创建另一个的子类。你可以认识到这一点 闻到,因为一个层次结构中的类名前缀是 与另一个层次结构中的前缀相同。
在书中 Refactoring in Large Software Projects: Performing Complex Restructurings, page 46作者显示以下并行继承:
然后他用组合解决了平行遗传并说:
在许多情况下,可以解决并行继承层次结构 这种方式只剩下一个继承层次结构,而 其他继承层次结构的类通过使用进行集成。
解决方案如下所示:
因此作者和Fowler得出结论,可以用
解决并行继承问题消除重复的一般策略是确保 一个层次结构的实例引用另一个层次结构的实例。
我看到的问题是类仍然存在,如果我添加一个新类,则必须添加一个新的'* ListView'类。
但对于这个问题,福勒说:
如果使用Move Method和Move Field,则引用的层次结构 上课消失了。
对于当前情况,这意味着我移动方法以显示实体 在实体类中?
所以这会伤害MVC校长吗?!
所以如何解决并行继承问题 尤其是在UI案例中?
1 Martin Fowler'重构:改进现有代码的设计'
[Book: Refactoring in Large Software Projects: Performing Complex Restructurings, page 46]
答案 0 :(得分:1)
根据具体情况,有几种方法可以解决这个问题。在这里,我提出了两种可能的解决方案:
注意:我会在示例中使用一些类似scala的伪代码,因为它简短易读
基于以下的实施:
最初,ListView
可能有一个默认适配器,需要其适配器实现某个接口,让我们称之为Nameable
。并使用它来呈现每个项目。
class BasicListViewAdapter extends ListAdapter[Nameable]
//on scala it would be a trait, but I'll call it interface just for the sake of the example
interface Nameable {
def getName():String
}
当然,并非所有类都将以完全相同的方式呈现。这可以通过使用适配器来解决。
class Partner implements Nameable
class Customer extends Partner {
def getName = { this.getClientCode + " " + this.getFullName }
/* some implementation*/
}
class Supplier extends Partner {
def getName = { this.getCompanyName }
/* some implementation*/
}
ListView
供应商将生成公司名称列表,ListView
客户将显示客户代码列表及其各自的名称(无论如何,只是一个例子)。
现在,如果我们想制作更复杂的列表,我们可以使用自定义适配器提供ListView。
class PhoneNumberAdapter extends ListAdapter[Supplier] { /*...*/}
val supliersWithPhoneNumbers = new ListView
supliersWithPhoneNumbers.useAdapter(new SupplierWithPhoneNumberAdapter)
使用此技术,您不再需要每个模型类一个ListView类,并且只为特殊情况定义自定义适配器。默认适配器和层次结构越好,所需的代码就越少。
再举一个例子,你可以看看https://codereview.stackexchange.com/questions/55728/a-generic-mvc-arrayadapter-class
如果您选择的语言允许(并且如果您在哲学上同意),则可以使用mixins或traits,而不是使用合成。我不会深入研究两者之间的差异,只需使用mixins(更多信息:Mixins vs. Traits)。
通过使用mixins,您可以更精确地分解行为,解锁各种新模式和解决方案(如果添加一些结构类型和其他功能,甚至更多)。
例如,回到ListView案例,每个渲染策略都可以通过ListView合并,如下所示:
trait NameAndPhoneNumber {
//we require this trait to be incorporated on some class of type ListView
this:ListView[{def getName:String }] =>
override def render = ...
}
//where ListView is covariant
new ListView[Supplier] with NameAndPhoneNumber
NameAndPhoneNumber
可以应用于多个类,而不仅仅是客户或供应商。
事实上,它可能会重构为:
new ListView[Supplier] with NameRendering with PhoneRendering
并使用 Stackable Traits 模式(更多信息(此处)[http://dl.acm.org/citation.cfm?id=2530439]和(此处)[http://www.artima.com/scalazine/articles/stackable_trait_pattern.html])
参考文献: