Java开发是否通常比C#/。NET涉及更多的子类化?


34

我最近开始研究Android开发。这使我回到了Java软件开发领域。我承认,上一次我使用Java时,我对OOP的了解不如现在(我认为)那么多。

在我的职业生涯中主要使用C#之后,我注意到Java和C#在继承使用方式方面的惊人差异。

在C#中,似乎在大多数情况下都可以避免继承。通常,可以通过使用.NET框架的具体类来完成当前的任务。

在Java中,从我从代码示例中收集的信息来看,Java框架似乎提供了许多接口或抽象类,这些接口或抽象类将由开发人员实现/扩展。

这似乎太大了,不能简单地归结为风格。这背后的原因是什么?我觉得直到我理解这一点,我才会写干净的Java代码。

此外,这是否仅限于Android SDK还是Java范围内的OOP方法?

或换种说法,

这两种语言(似乎鼓励)比另一种或多或少使用继承的设计是什么?

如果语言对继承的处理相同,并且假设我的观察是有效的,则意味着这与框架/库的设计有关,而与语言无关。这种设计的动机是什么?


1
这是真的。Java有太多接口。我很想知道为什么这种开发人员行为对于特定语言是常见的。与其他项目相比,我在Java项目中更经常看到这种情况。一定有一个原因,而不仅仅是一个意见。
Reactgular

1
@MathewFoscarini这只是您的意见。在我参与的Java项目中,开发人员倾向于避免像瘟疫一样继承。这里没有什么权威,只有我的意见。想投票吗?
蚊蚋

2
几乎不需要使用Java从另一个类派生一个类。相反,您可以实现接口以实现多态性并实现组成的对象并代理方法调用以实现精简功能。
2013年

1
@ThinkingMedia通常,Java被OSS狂热者/纯粹主义者所淹没。学术原则是最重要的问题。.Net开发人员是注重完成工作的实用主义者。他们认为工作代码比最干净的代码更有价值。
安迪2015年

Answers:


31

这似乎太大了,不能简单地归结为风格。这背后的原因是什么?

我的理解是,它在很大程度上一个简单的风格决定。好吧,也许不是风格,而是语言/环境的成语。Java标准库开发人员遵循一套设计准则,.NET开发人员遵循另一套设计准则(尽管他们有能力了解Java的方法如何工作)。

实际语言中很少有鼓励或劝阻继承的内容。只有两件事使我感到重要:

  1. .NET在泛型生命周期的较早阶段就引入了泛型,然后才实施了太多的非泛型代码。另一种选择是继承很多类型专门化的东西。

  2. 更大的变化是.NET支持委托。在Java中,您必须使用(匿名)继承来提供最基本的可变功能。这导致代码在设计上如何利用委托或避免在Java中执行代码所需的笨拙的继承结构方面存在较大差异。


3
我认为这个答案提供了一个非常合理的解释。特别是关于匿名继承代替委托人的观点。我已经观察了很多。谢谢。
MetaFight

3
不要忘记.NET 3.5中引入的匿名类型和lambda语法/表达式树。当然,在.NET 4中可以选择加入动态类型。现在,毫无疑问,它几乎是一种混合范式语言,并非严格地面向对象。
亚伦诺特,2013年

是的,根据我的使用经验(包括在同一人同时使用两种语言的混合项目中),人们倾向于在编写Java编码时使用大量较小的类,而在编写Java时倾向于使用较少数量的较大类(趋向于神类)使用C#。在两种情况下都使用相同的样式故意对相同的东西进行原型制作,最终得到的类数类似(使用局部类,即使使用C#也可能会得到更多的代码文件)。
jwenting 2014年

6

这些是非常不同的语言,尤其是在该领域。假设您有一堂课。在这种情况下,我们将其设为用户控件,例如文本框。称之为UIControl。现在我们要把它放在另一个类中。在这种情况下,由于我们在示例中使用的是UI,因此我们将其称为CleverPanel类。我们的CleverPanel实例将由于各种原因想知道其UIControl实例发生的事情。这该怎么做?

在C#中,基本方法是检查各种事件,设置将在触发每个有趣事件时执行的方法。在缺少事件的Java中,通常的解决方案是将具有各种“事件”处理方法的对象传递给UIControl方法:

boolean  stillNeedIt =  ... ;
uiControl.whenSomethingHappens( new DoSomething()  {
    public void resized( Rectangle r )  { ... }
    public boolean canICloseNow()  { return !stillNeedIt; }
    public void closed()  { ... }
    ...
} );

到目前为止,C#和Java之间的区别并不深远。但是,我们拥有C#不需要的DoSomething接口。同样,此接口可能包含很多在大多数时候不需要的方法。在C#中,我们只是不处理该事件。在Java中,我们创建一个为所有接口方法DoSomethingAdapter提供空实现的类。现在,我们将DoSomething替换为DoSomethingAdapter,并且完全不需要编写任何方法即可进行干净的编译。我们最终只是覆盖使程序正常运行所需的方法。因此,我们最终需要一个接口,在Java中使用继承来匹配我们对C#中的事件所做的操作。

这是一个示例,而不是全面的讨论,但它提供了Java为什么与C#相比继承如此之多的基础。

现在,为什么Java这样工作?灵活性。传递给whenSomethingHappens的对象可以完全从其他地方传递给CleverPanel。可能是几个CleverPanel实例应将其传递给类似UIControl的对象,以帮助某个地方的CleverWindow对象。 或者,UIControl可以将其交给组件之一。

另外,在某处可能会有DoSomething实现,而不是适配器,后面有成千上万行代码。我们可以创建一个新的实例和传递。我们可能需要重写一种方法。Java中的一个常见技巧是使用一个类似以下方法的大型类:

public class BigClass implements DoSomething  {
    ...many long methods...
    protected int getDiameter()  { return 5; }
}

然后在CleverlPanel中:

uiControl.whenSomethingHappens( new BigClass()  {
    @Override
    public int getDiameter()  { return UIPanel.currentDiameter; }
} );

开源Java平台做了很多这样的工作,这往往促使程序员做更多的事情-都是因为他们以它为例,只是为了使用它。我确实认为该语言的基本设计落后于Sun的框架设计, Java程序员则在使用该框架时使用这些技术。

在Java中动态创建类确实很容易。匿名或已命名的类仅需要在用一种方法深层埋藏的一小段代码中进行引用。它可以是全新创建的,也可以通过对非常大的现有类进行少量修改来创建。(现有类可以在其自己的文件中位于顶层,也可以嵌套在顶层类中,或者仅在单个代码块中定义)。新的类实例可以完全访问所有创建对象的数据。新实例可以在整个程序中传递和使用,代表创建它的对象。

(顺便说一句,请注意,这里继承的大量使用(就像Java中的其他地方一样)只是出于DRY的目的。它允许不同的类重用相同的代码。还要注意Java中继承的简便性鼓励了这一点。 )

同样,这不是一个全面的讨论。我只是在这里刮擦表面。但是,是的,Java和C#之间使用继承的方式存在惊人的差异。 在这方面,它们是非常不同的语言。这不是你的想象力。


注意:通过扩展充满空实现的抽象类,可以避免提供任何不必要的方法。这样,您可以有选择地覆盖执行某些操作的方法。虽然不那么难看,但它意味着继承的另一个层次。
彼得·劳瑞

-2

Java和C#之间处理继承的方式绝对没有区别。当您实际使用继承或组合时,绝对是设计决定,绝不是Java或C#鼓励或劝阻的事情。我建议阅读这篇文章

希望我能帮上忙!


5
您是在谈论语言本身,但我认为问题还在于库和常用用法。
svick

3
但是在其余的语言中,有一些古怪的地方鼓励在Java中进行额外的继承。请参见RalphChapin的答案
2013年
By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.