Oop 如何解决UI案例中的并行继承
我很难理解如何解决并行继承问题 并行继承的定义 Fowler对并行继承的定义如下[1,第68页]: 并行继承层次结构实际上是散弹枪的一个特例 手术。在这种情况下,每次创建一个类的子类, 您还必须创建另一个的子类。你可以认识到这一点 因为一个层次结构中类名的前缀是 与另一层次结构中的前缀相同 问题 书中 作者将显示以下并行继承: 然后,他用合成法解决了并行继承问题,并说: 在许多情况下,并行继承层次结构可以在 这种方式只剩下一个继承层次结构,而 其他继承层次结构的类通过使用进行集成 解决方案如下所示: 因此,作者和Fowler得出结论,并行继承可以用 消除重复的总体策略是确保 一个层次结构的实例引用另一个层次结构的实例 我看到的问题是类仍然存在,如果我添加一个新类,则必须添加一个新的“*ListView”类。 但对于这个问题,福勒说: 如果使用“移动方法”和“移动字段”,则引用对象上的层次结构 阶级消失了 对于当前情况,这意味着我移动该方法以显示实体 在实体类中 这会不会伤害MVC负责人 问题: 那么如何解决并行继承呢 尤其是在UI情况下? 资料来源: Martin Fowler“重构:改进现有代码的设计”Oop 如何解决UI案例中的并行继承,oop,user-interface,inheritance,Oop,User Interface,Inheritance,我很难理解如何解决并行继承问题 并行继承的定义 Fowler对并行继承的定义如下[1,第68页]: 并行继承层次结构实际上是散弹枪的一个特例 手术。在这种情况下,每次创建一个类的子类, 您还必须创建另一个的子类。你可以认识到这一点 因为一个层次结构中类名的前缀是 与另一层次结构中的前缀相同 问题 书中 作者将显示以下并行继承: 然后,他用合成法解决了并行继承问题,并说: 在许多情况下,并行继承层次结构可以在 这种方式只剩下一个继承层次结构,而 其他继承层次结构的类通过使用进行集成 解决方案如下
根据具体情况,有几种解决方法。在此,我提出两种可能的解决方案: 注意:我将在示例中使用一些类似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提供一个自定义适配器
class PhoneNumberAdapter extends ListAdapter[Supplier] { /*...*/}
val supliersWithPhoneNumbers = new ListView
supliersWithPhoneNumbers.useAdapter(new SupplierWithPhoneNumberAdapter)
使用这种技术,您不再需要为每个模型类定义一个ListView类,而只需要为特殊情况定义自定义适配器。默认适配器和层次结构越好,所需的代码就越少
再举一个例子,你可以看看
混合蛋白/性状 如果你选择的语言允许(如果你在哲学上同意),你可以使用混合词或特征,而不是使用构图。我不会深入讨论两者之间的差异,只使用mixin(更多信息:) 通过使用mixin,您能够以更精细的方式分解行为,解锁各种新模式和解决方案(如果您添加了一些结构类型和其他功能,甚至会更复杂) 例如,回到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
其中,name和phonenumber
可以应用于多个类别,而不仅仅是客户或供应商。
事实上,它可能会被重构为:
new ListView[Supplier] with NameRendering with PhoneRendering
并利用可堆叠特征模式(更多信息(此处)[和(此处)[)
参考资料:
- 一个案例:
- (可堆叠特征模式)[