如何解决UI案例

时间:2015-06-23 11:23:33

标签: oop user-interface inheritance

我有一个问题需要了解如何解决并行继承问题。

并行继承的定义

Fowler定义并行继承如下[1,第68页]:

  

并行继承层次结构实际上是霰弹枪的一个特例   手术。在这种情况下,每次创建一个类的子类时,   你还必须创建另一个的子类。你可以认识到这一点   闻到,因为一个层次结构中的类名前缀是   与另一个层次结构中的前缀相同。

问题

在书中 Refactoring in Large Software Projects: Performing Complex Restructurings, page 46作者显示以下并行继承:

enter image description here

然后他用组合解决了平行遗传并说:

  

在许多情况下,可以解决并行继承层次结构   这种方式只剩下一个继承层次结构,而   其他继承层次结构的类通过使用进行集成。

解决方案如下所示:

enter image description here

因此作者和Fowler得出结论,可以用

解决并行继承问题
  

消除重复的一般策略是确保   一个层次结构的实例引用另一个层次结构的实例。

我看到的问题是类仍然存在,如果我添加一个新类,则必须添加一个新的'* ListView'类。

但对于这个问题,福勒说:

  

如果使用Move Method和Move Field,则引用的层次结构   上课消失了。

对于当前情况,这意味着我移动方法以显示实体 在实体类中?

所以这会伤害MVC校长吗?!

问题

所以如何解决并行继承问题 尤其是在UI案例中?

来源:

1 Martin Fowler'重构:改进现有代码的设计'

[Book: Refactoring in Large Software Projects: Performing Complex Restructurings, page 46]

1 个答案:

答案 0 :(得分:1)

根据具体情况,有几种方法可以解决这个问题。在这里,我提出了两种可能的解决方案:

注意:我会在示例中使用一些类似scala的伪代码,因为它简短易读

List Adapter&泛型

基于以下的实施:

最初,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或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]

参考文献: