AWT组件和自定义接口类型:如何编写好的OOP代码?

时间:2012-04-22 17:39:59

标签: oop design-patterns

假设我有一个Swing GUI,它必须以两种不同的方式显示某种类型的信息。从设计模式的角度来看,可能会在这里使用策略模式:创建一个接口,定义显示组件和客户端之间的通信如何工作:

public interface Foo {
  void showData(Data bar)
}

然后实际操作由实现Foo的不同组件完成,并且可以创建和插入以执行实际工作。

现在,如果真正的组件是java.awt.Components会发生什么?正如我所看到的,它会导致类型转换混乱,因为Component是一个类。让我们假设一个像这样的实现:

public class Baz extends Component implements Foo {
  ...
}

如果我想传递类Baz的对象,这些方法可以使用“Component”作为参数类型或“Foo”。问题是某些方法需要Component和Foo的对象(例如,因为它们将对象添加到JPanel,然后提供调用接口方法showData()的数据)。

在我看来,我有一些选择可以实现这一目标:

  • 我可以将引用传递给Component并转换为Foo。之前,我必须检查引用是否是Foo的实例,我必须处理不满足此要求的情况。另一个问题是我必须向客户端传达Component传递的方法也必须实现Foo,这很笨拙且容易出错。
  • 我可以用Foo做同样的事情
  • 我可以将一个方法“Component getComponent()”添加到Foo接口,并且实现将始终返回“this”。这个样板方法可以放在Component的抽象子类中。这个解决方案意味着我不想要的接口方法和我不需要的额外子类。
  • 我可以将两个引用,一个Component和一个Foo引用传递给同一个对象。但在内部,我必须确保两个引用都属于同一个对象。我必须处理不满足此要求的情况。
  • 我可以使用Component的抽象子类,并使用抽象方法定义接口。这将允许我以类型安全的方式传递引用,但打破了良好的OOP实践:保持接口和实现分离,以及接口隔离原则。

因此,所有这些解决方案仅仅是解决方法。我有什么解决方案吗?我该怎么办?

1 个答案:

答案 0 :(得分:0)

我会像你提到的那样使用策略设计模式,但也许在不同的上下文中。尝试将FooComponent“套在一个”类中的问题是,您可能需要复制代码的实现组合。

例如,假设您有Component的以下实现: (自从我使用Swing以来已经太久了,这些类可能不存在)

  • 的JPanel
  • 的JButton
  • JMenu的

您还有Foo

的以下实现
  • MyFoo
  • HisFoo
  • OurFoo
  • WhatTheFoo

想象一下这些的所有组合:那是什么叫做类爆炸。这是战略模式的经典理由。

我会创建一种容器类,它为每个所需的类使用HAS-A关系,而不是使用IS-A关系,如下所示: (我是一名c ++程序员,所以你必须原谅混合代码:)

class ComponentFooHandler {
  Component component_;
  Foo fooImpl_;

  inline Foo getFoo()  {return fooImpl_;}
  void setFoo(Foo f)   {fooImpl_ = f;}

  Component getComponent()        {return component_;}
  void setComponent(Component c)  {component_ = c;}

  void doAction() {
    component_.someAction();
    fooImpl_.anotherAction();
  }
}

然后,您必须单独创建Foo的不同实现。然后可以根据需要组合ComponentFoo实现,而不必复制Foo impl代码。另请注意,您可以调用类似于doAction()的方法,这些方法可以在FooComponent上运行而不知道其详细信息,类似于模板模式。

解决原始问题的问题:

  • 当需要Component时,请在处理程序实例
  • 上调用getComponent()
  • 当需要Foo时,请在处理程序实例
  • 上调用getFoo()
  • 我会避免在一个方法中创建需要两者的方法,并将方法args拆分为2
  • 或者只考虑绕过ComponentFooHandler