让我们从基础开始,关于类最重要的事情是:子类始终也是超类的完整实例。所以如果你在超类中定义了一个字段变量,当你创建子类实例时,该字段始终会被创建。你可以使用super.getVariable()在子类中获取那个变量,以重用字段(类变量、字段、标志,在面向对象编程中都是一样的)。但是你也可以直接从外部调用subclassInstance.getVariable()来获取相同的字段(不需要通过子类更改)。因此,通常情况下你根本不需要在子类中调用"super",因为你通常只想从外部获取/设置其超类(包括抽象类)的字段。由于应该始终将字段变量设置为私有,我建议永远不要调用"super"来访问任何字段变量(因为即使使用super,你也无法访问超类的私有方法/字段……实际上这是Java中最大的错误之一,因为它无法向其他类提供完全封装的类树……所以你通常需要调用像super.getField()这样的protected方法,这很烦人,但却是必须的)。
现在让我们谈谈数据模型:你有modelA和modelB。你可以从超类或Object中继承它们。但是如果你仅从Object中继承,你可以定义一个简单的(Java!)接口,并将此接口实现到modelA和modelB中。然后你只需通过接口处理这两个类(它们都是“接口对象”并且可以被通用地处理)。如果你有由modelA和modelB组成的modelC,你只需在modelC中使用这两个模型的实例(有时也称为“解引用”),无需编写更多代码。因此,你应该尽可能选择这些模型变得小而简单(“beans”)。组件化实现是数据结构的常规方式。
如果你有GUI或表单,情况就不同了。你可能有很多共同的代码,而且你不想将这些代码拆分成几十个不同的类,然后在控制器/Presenter类中将组件合并在一起。所以你可以定义一个抽象类,其中包含所有共享字段/标志以及若干方法来访问和更改它们。然后,你从formA和formB中调用这些公共方法并重用代码。
集合论对你有什么意义吗?你有两个圆,A和B,它们交叉部分是抽象类,子类formA和formB是集合差异。学习编写正确的程序……就是理解集合论。;-)
简单来说:表单
Foo的大部分代码将在抽象超类
Foobar中,这个类将能够处理
A和
B。然后你从中继承
Foo和
Bar,虽然
C可能大多数情况下仍然是
Foobar的子集,但你可以在
Bar中添加处理
C的功能,这就是集合差异。
最终,
Bar在任何时候都不会是
Foo,它们两个都只是
Foobar。你有一些新的共享字段/标志吗?没问题,将它们的代码迁移到
Foobar中,你可以在两个子类中使用它!
但是,如果有一天你需要一个略有不同于
Foo的第三个组件
FooToo怎么办?没问题,将
FooBarFoo作为继承自
FooBar的抽象类,然后创建
Foo和
FooToo作为子类。最终的结果将是一个类树,其中根通常是抽象类,叶子是真正的类,这种结构提供了代码的最大化重用(并且不更改类名,因此您无需更改已经使用类
Foo的任何其他代码)。
你说你将在表单(或其Presenter)中实现setter/getter?那么你必须使用模型
modelA和
modelB(但不是模型C,因为C仅在
Bar中使用而不是
Foo)。这些模型用作包装器,在
Foo和
Bar之间传输数据。这个数据流应该由Presenter控制,而不是由
Foo或
Bar控制。
所以你的问题最终就是:Presenter是什么?实际上,Presenter是运行GUI组件和数据模型的代码。它是一个“框架”,一方面使用GUI组件,另一方面使用数据模型的getter/setter。它是两个层之间的中间件,GUI层和数据层,甚至在不同的GUI组件和不同的数据模型之间。
因此,通常只有两种方法可以做到这一点:没有Presenter/Controller或者有它。如果没有,你需要将很多Swing组件代码复制粘贴到Presenter类中。那又怎样?没错,当你使用Swing组件时,你将始终使用(M)VP模式,不可能做出不同的选择!
所以说,为了创建一个框架,你需要使用组件设计,因为你想要为使用你的框架的程序员提供最大的灵活性。但是一个高效的系统并不等同于一个框架,这是许多框架程序员的误区。因此,如果一个框架程序员告诉你“基于组件的实现就是一切”,那么他可能是错的。仅仅因为他正在为其框架编写组件,并不意味着你需要为你的Presenter做同样的事情!
所以当我们开始讨论GUI组件与GUI表示时,我们可以创建“尽可能多的Presenter组件”,就像你可以使用方法“include(...)”将简单的HTML网站制作成几十个PHP网站一样。但我向你保证,基于组件的设计并不总是提高代码的可维护性!如果我只需要一个类来完成某个任务,并且我能够清晰和易读地完成它,我宁愿选择一个类而不是十个类。一个Presenter=一个类,或者更具体地说:一个GUI框架/选项卡=一个类。
再次,如果你有两个相似的框架/选项卡,但它们不同,该怎么办呢?将共享的代码迁移到抽象类中,并创建2个子类,对吧?
不,你首先需要考虑这些GUI共享了什么。它们有共享的标志吗?那么将标志移到一个抽象超类中。但是它们只是表现不同吗?那么你只需要在同一个类中实现两种不同的方法,并在需要时调用它们。这是最重要的。
用你的话说:GUI
Pres1 共同使用
Foo、
Bar、
A、
B 和
C。如果GUI
Pres2 只有不同的标志,那么它就在另一个类中。否则,你将设置一个标志
Pres1 和一个标志
Pres2 并在方法内检查这个标志。通过
if(flag="Pres1"){} else if(flag="Pres2"){}
这样做,你将获得最大的灵活性和代码可重用性。
不要将Java类视为不灵活、不可重用、不可更改的东西。如果你是一位优秀的程序员,当需要时,你会凭直觉改变程序的结构。你不需要考虑人为的概念,你只需要理解面向对象编程模式。
“组件”总是意味着“带有构造函数的东西”。但是,有时你会使用一个方法而不是组件来完成某些任务!因此,如果有人告诉你“基于组件的设计就是一切”,他实际上是在告诉你“基于构造函数的设计就是一切”。但是要创建构造函数,你需要有字段变量/标志!没有字段变量,仅仅为了制作而创建一个新类是完全没有意义的。
注意:“组件”指的不是一个方法。显然,在处理GUI类中,您将使用许多方法轻松处理事情,因此最终您只需调用几个方法即可。因此,请不要混淆组件和方法!我始终建议采用强大的方法导向设计,因为这关乎使用更少的代码行。因此,尽可能定义更多的方法......但也尽可能少定义类/组件。