java 空抽象类是一种不好的做法,为什么?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/1749477/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
Are empty abstract classes a bad practice, and why?
提问by Antoine Claval
We have several empty abstract class in our codebase. I find that ugly. But besides this very stupid reason (ugliness), should I refactor it (into empty interface e.g.) ?
我们的代码库中有几个空的抽象类。我觉得那很丑。但是除了这个非常愚蠢的原因(丑陋)之外,我还应该重构它(例如,变成空界面)吗?
Otherwise, the code is robust and well tested. So if it's only for a "aesthetic" reason, I will pass and let the empty abstract classes remain.
否则,代码是健壮的并且经过良好测试。所以如果只是出于“审美”的原因,我会通过并保留空的抽象类。
What do you think?
你怎么认为?
EDIT :
编辑 :
1) By "empty abstract class", I mean something like :
1)通过“空抽象类”,我的意思是:
public abstract class EmptyAbstractClass {}
2) The reason for the "emptiness" : Hibernate. I don't master this persistence framework at all. I just understand that an interface cannot be mapped to a table, and for this technical reason, a class has been preferred to an interface.
2)“空”的原因:休眠。我根本不掌握这个持久化框架。我只是明白接口不能映射到表,由于这个技术原因,类比接口更受青睐。
采纳答案by Michael Rutherfurd
Sounds to me like this is the result of creating an object heirarchy that ended up not having any common functionality at it's top most levels. I suspect that the immediate subclasses are abstract themselves or at least have subclasses of their own. The other likelyhood is that your code has a lot of instanceof functions scattered throughout it.
在我看来,这是创建对象层次结构的结果,该层次结构最终在其最顶层没有任何通用功能。我怀疑直接子类本身是抽象的,或者至少有它们自己的子类。另一种可能是你的代码有很多散布在其中的 instanceof 函数。
The empty topmost level isn't a huge deal in and of itself but I would check to verify that no common functioanlity actually exists. Assuming it does exist I would look at pulling the common features up in the parent classes. I would definately keep a look out for instanceof and think seriously about refactoring it (refer Refactoring to Patterns (Kerievsky) for examples).
空的最高级别本身并不是什么大问题,但我会检查以确认实际上不存在共同的功能。假设它确实存在,我会考虑在父类中提取通用功能。我肯定会留意 instanceof 并认真考虑重构它(参考 Refactoring to Patterns (Kerievsky) 的例子)。
回答by Vincent Ramdhanie
Interfaces are preferable in this case because it makes your code more robust for maintenance. That is, you can only extend a single class but you may implement many interfaces.
在这种情况下,接口更可取,因为它使您的代码更易于维护。也就是说,您只能扩展一个类,但可以实现多个接口。
If there is absolutely no direct effect right now I would not touch it. If the maintenance event turns up that requires you to make a change then I would refactor it since I am already in the code.
如果现在绝对没有直接影响,我不会碰它。如果出现需要您进行更改的维护事件,那么我会重构它,因为我已经在代码中了。
In other words if it ain't broke don't fix it.
换句话说,如果它没有坏,就不要修理它。
回答by David Seiler
The question to ask is: "What do I want to do with this code that I can't do, or find hard to do, because these empty abstract classes are there?" If the answer is 'nothing', you should leave them alone. If the answer is "something", it may well be worthwhile to remove them - but if you can, speak to the people who created them first, just to make sure there isn't some subtle purpose to them. For example, perhaps your code uses reflection to find all instances of a particular ABC and do special things to them, in which case your refactoring could break the code in subtle ways.
要问的问题是:“我想用这段代码做什么,因为这些空的抽象类在那里我不能做,或者很难做?” 如果答案是“没有”,您应该让他们独自一人。如果答案是“某物”,删除它们可能是值得的——但如果可以,请与首先创建它们的人交谈,以确保它们没有任何微妙的目的。例如,也许您的代码使用反射来查找特定 ABC 的所有实例并对它们执行特殊操作,在这种情况下,您的重构可能会以微妙的方式破坏代码。
回答by extraneon
It is not necessarily more ugly than the alternative, which may be repeating code.
它不一定比替代方案更丑陋,后者可能是重复代码。
In an ideal world you would be able to model using only interfaces. for example: Vehicel -> Car -> Pontiac.
在理想的世界中,您将能够仅使用接口进行建模。例如:车辆 -> 汽车 -> 庞蒂亚克。
But there may be logic which is the same for all Vehicels, so an interface is not appropriate. And you don't have logic specific to Cars. But you do want a Car abstraction because your TrafficLightController wants to distinguish between Cars and Bicycles.
但是可能存在所有Vehicles相同的逻辑,因此接口是不合适的。而且您没有特定于汽车的逻辑。但是您确实需要 Car 抽象,因为您的 TrafficLightController 想要区分 Cars 和 Bicycles。
In that case you need to make and abstract Car.
在这种情况下,您需要制作和抽象 Car。
Or you can make an interface Vehicle, a VehicleImpl implements Vehicle, an interface Car extends Vehicle, an interface Pontiac implements Car, and a PontiacImpl implements Pontiac extends VehicleImpl. I personally dislike a parallel hierarchy of interfaces for the sake of preventing an empty abstract class more than an empty abstract class.
或者你可以做一个接口 Vehicle,一个 VehicleImpl 实现 Vehicle,一个接口 Car extends Vehicle,一个接口 Pontiac 实现 Car,一个 PontiacImpl 实现 Pontiac extends VehicleImpl。我个人不喜欢接口的并行层次结构,因为它比空抽象类更能防止空抽象类。
So I guess it's a matter of taste.
所以我想这是一个品味问题。
One caveat; if you use a lot of proxied classes like with Spring and some testing frameworks a parallel interface hierarchy might well result in less unexpected errors.
一个警告;如果您使用大量代理类,例如 Spring 和一些测试框架,并行接口层次结构很可能会减少意外错误。
回答by Pascal Thivent
Empty abstract classes don't make any sense to me, abstract classes should be used to inherit some behavior. So, I tend to agree, it's a pretty ugly design and a very bad use of abstract classes, marker interfaces should be preferred. So you have two options:
空的抽象类对我来说没有任何意义,抽象类应该用于继承某些行为。所以,我倾向于同意,这是一个非常丑陋的设计,并且对抽象类的使用非常糟糕,应该首选标记接口。所以你有两个选择:
- Wait till you need to extend another class for a real need and get annoyed by the abstract class to replace it by an interface.
- Don't wait and fix the design.
- 等到您需要为真正的需要扩展另一个类,并且对抽象类感到恼火时,将其替换为接口。
- 不要等待并修复设计。
In this particular situation, it is true that the actual design doesn't really hurt, for now, so you can live with it. However, I think replacing these abstract classes is a pretty easy refactoring (make them interfaces and replaces extendswith implementswhere you get compilation errors) and I really can't see what could get broken so I would go for it.
在这种特殊情况下,目前的实际设计确实没有真正受到伤害,因此您可以接受它。但是,我认为替换这些抽象类是一个非常简单的重构(使它们成为接口并替换extends为implements出现编译错误的地方)而且我真的看不出什么会被破坏,所以我会去做。
Personally, and people may of course disagree, I don't like being too defensive. With rules like if it's ain't broke, don't fix it, you'll never refactor anything ("my tests passes, why should I refactor?"). Freezing the code is definitely not the right solution, testing aggressively is the right solution.
就我个人而言,当然人们可能不同意,我不喜欢过于防御。有了这样的规则,如果它没有被破坏,就不要修复它,你永远不会重构任何东西(“我的测试通过了,我为什么要重构?”)。冻结代码绝对不是正确的解决方案,积极测试才是正确的解决方案。
回答by BlairHippo
Ask yourself this question: If, as a result of your refactoring, something breaks in production and your continued employment depends on how well you justify your decision to spend time fixing something that wasn't actually broken, what do you say?
问问自己这个问题:如果由于重构而导致生产中断,而您的继续工作取决于您决定花时间修复实际上并未中断的事情的合理性,您会怎么说?
"It was ugly and aesthetically offensive to me" isn't an answer I'd like to stake my job on.
“这对我来说很丑陋,而且在美学上令人反感”并不是我想以此为赌注的答案。
At this stage, I say play it safe and live with the Ugly.
在这个阶段,我说要小心谨慎,与丑陋的人一起生活。
回答by BalusC
The key is that you can extend from only oneabstract class, while you can implement moreinterfaces.
关键是你可以只从一个抽象类扩展,同时你可以实现更多的接口。
Apparently the "empty abstract class" design desicion was made so that it prevents the implementing class from extending from another classes.
显然,“空抽象类”的设计决定是为了防止实现类从另一个类扩展。
If it was me I'd let it go, otherwise it might break. Best is still to contact the original developers and ask for reasoning (and add them as comments in the abstract class for your and future convenience).
如果是我,我会放手,否则它可能会坏掉。最好还是联系最初的开发者并要求推理(并将它们作为注释添加到抽象类中,以方便您和未来的使用)。
回答by Monachus
According to object oriented programming theory the main purpose for inheritance is polymorphism, code reuse and encapsulation. An empty abstract class (and when i say this i mean truly empty, no constructors, no methods, no properties. nothing!) does not achieve any of the three goals hoped by this programming technique. It is the equivalent to
if(true){...}. changing it to an interface does not really makes it any better.
根据面向对象编程理论,继承的主要目的是多态性、代码重用和封装。一个空的抽象类(当我说这个时我的意思是真正的空,没有构造函数,没有方法,没有属性。什么都没有!)不能实现这种编程技术所希望的三个目标中的任何一个。它相当于
if(true){...}。将其更改为界面并不会真正使它变得更好。
If you want to refactor the code i would advise you to think in the direction opposite to the one you are thinking, what i mean by this is: try to abstract properties, methods and constructors from all classes that share a abstract parent class.
如果您想重构代码,我建议您按照与您正在思考的方向相反的方向思考,我的意思是:尝试从共享抽象父类的所有类中抽象属性、方法和构造函数。
This is hard work with little reward in the short term but it increases the maintainability of the code dramatically since a core logic change would have to be done only once. I suspect the reason for using those empty abstract classes is to identify a group of classes that must share something in common otherwise what would be the difference between Objectand the abstract class
这是一项艰苦的工作,短期内回报甚微,但它极大地提高了代码的可维护性,因为核心逻辑更改只需进行一次。我怀疑使用那些空的抽象类的原因是为了确定一组必须共享一些共同点的类,否则Object和抽象类有 什么区别
回答by TofuBeer
If you have the following pattern you will find it to be the most flexible:
如果您有以下模式,您会发现它是最灵活的:
interface Fooable
{
void foo();
void bar();
}
abstract class AbstractFoo
implements Fooable
{
}
class Foo
extends AbstractFoo
{
public void foo()
{
}
public void bar()
{
}
}
This way you can always pass by the interface but if you later find that you have code that can be common you can put it in the abstract class without having to make changes to all of the classes.
通过这种方式,您始终可以通过接口,但是如果您后来发现您的代码可能很常见,您可以将它放在抽象类中,而无需对所有类进行更改。
Unless you have a good reason for not doing that pattern (and I suspect you don't in this case) I would suggest using it. This can wind up with empty abstract classes but I think it is ok (a little odd, but ok).
除非您有充分的理由不这样做(我怀疑在这种情况下您没有这样做),否则我建议使用它。这可能会以空的抽象类结束,但我认为还可以(有点奇怪,但还可以)。
If there truly are no methods in the interface or only one then I would skip the abstract class.
如果接口中确实没有方法或只有一个方法,那么我将跳过抽象类。
From a compiler/functional point of view there is no real difference between an interface and an abstract class where all method are abstract. The interface will be more flexible than the abstract class, and the interface + abstract class will be the most flexible of all.
从编译器/功能的角度来看,接口和所有方法都是抽象的抽象类之间没有真正的区别。接口会比抽象类更灵活,接口+抽象类将是最灵活的。
If it were my code I'd make the change to them being interfaces...
如果是我的代码,我会将它们更改为接口...
回答by Jay
The obvious questions are, Why was it put there? and How is it used?
显而易见的问题是,为什么把它放在那里?以及它是如何使用的?
My guess is that, either (a) This is the vestige of some false start. An early draft had some data or functions in the abstract class, but as the programmer worked these were all moved elsewhere, until there was nothing left but an empty shell. But more likely (b) At some point there is code that says "if (x instanceof ...". I think this is bad design, basically using a class membership as a flag. If you need a flag, create a flag, don't pretend you're being "more object-oriented" by creating a class or an interface and then using it as a flag. That may fit some textbook definition of better coding but in reality just makes code more confusing.
我的猜测是,要么(a)这是一些错误开始的痕迹。早期的草稿在抽象类中有一些数据或函数,但随着程序员的工作,这些都被移到了别处,直到只剩下一个空壳。但更有可能的是(b)在某些时候有代码说“if(x instanceof ...”。我认为这是糟糕的设计,基本上使用类成员作为标志。如果你需要一个标志,创建一个标志,不要通过创建类或接口然后将其用作标志来假装您“更加面向对象”。这可能符合一些教科书对更好编码的定义,但实际上只会使代码更加混乱。
+1 to Monachus for pointing out that an empty interface is no better than an empty abstract class. Yes, yes, I know Sun did that themselves with Cloneable, but I think that was a lame solution to the problem.
+1 Monachus 指出空接口并不比空抽象类好。是的,是的,我知道 Sun 自己使用 Cloneable 做到了这一点,但我认为这是解决问题的一个蹩脚的解决方案。

