组合和继承是一样的吗? 如果我想实现组合模式,我如何在Java中做到这一点?
当前回答
两个类之间的继承,其中一个类扩展了另一个类,建立了“IS A”关系。
另一端的组合包含类中另一个类的实例,建立了“Has A”关系。组合在java中是很有用的,因为它在技术上便于多重继承。
其他回答
@Michael Rodrigues给出的答案不正确(我道歉;我不能直接评论),这可能会导致一些混乱。
接口实现是一种继承形式…当你实现一个接口时,你不仅继承了所有的常量,你还将你的对象提交为接口指定的类型;这仍然是一种“是”的关系。如果汽车实现了Fillable,那么汽车“是-a”Fillable,并且可以在任何需要使用Fillable的代码中使用。
组合从根本上不同于继承。当您使用组合时,您(如其他回答所示)在两个对象之间建立了“has-a”关系,而不是使用继承时所建立的“is-a”关系。
所以,从其他问题中关于汽车的例子来看,如果我想说一辆汽车“有一个”油箱,我会使用如下的组合:
public class Car {
private GasTank myCarsGasTank;
}
希望这能消除任何误解。
合成就像它听起来一样-你通过插入部分来创建一个对象。
这个答案的其余部分错误地基于以下前提。 这是通过接口完成的。 例如,使用上面的Car例子,
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
用一些标准的理论组件,你就可以构建你的对象。然后,你的工作就是填写房子如何保护它的居住者,以及汽车如何保护它的居住者。
继承则正好相反。您从一个完整(或半完整)对象开始,然后替换或覆盖您想要更改的各种位。
例如,机动车辆可能带有可燃料方法和驱动方法。您可以保留Fuel方法,因为给摩托车和汽车加油是一样的,但您可以重写Drive方法,因为摩托车的运行方式与汽车非常不同。
通过继承,一些类已经完全实现,而其他类的方法必须重写。在合成中什么都没有给你。(但是你可以通过调用其他类中的方法来实现接口,如果你碰巧有一些东西的话)。
组合被认为是更灵活的,因为如果你有一个像iUsesFuel这样的方法,你可以在其他地方有一个方法(另一个类,另一个项目),它只关心处理可以被燃料的对象,不管它是汽车、船、炉子、烧烤等等。接口要求那些声称实现了该接口的类实际上拥有该接口的全部方法。例如,
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
然后你可以在其他地方有一个方法
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
奇怪的例子,但它表明这个方法并不关心它在填充什么,因为对象实现了iUsesFuel,它可以被填充。故事结束了。
如果你使用继承,你将需要不同的FillHerUp方法来处理机动车辆和烧烤,除非你有一些相当奇怪的“ObjectThatUsesFuel”基础对象来继承。
构图是指某物由不同的部分组成,并且它与这些部分之间有很强的关系。如果主体死亡,其他部分也会死亡,他们就不能拥有自己的生命。一个粗略的例子就是人体。取出心脏,其他部分就会消失。
继承就是你取已经存在的东西并使用它。没有很强的关系。一个人可以继承他父亲的财产,但他也可以不继承。
我不知道Java,所以我不能提供一个例子,但我可以提供一个概念的解释。
遗产怎么会是危险的?
让我们举个例子
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1)正如上面的代码所示,类Y与类X具有很强的耦合性。如果超类X发生任何变化,Y可能会急剧断裂。假设在未来的类X中实现了一个具有以下签名的方法work
public int work(){
}
改变是在类X中完成的,但它将使类Y不可编译。所以这种依赖可以上升到任何程度,这是非常危险的。每次超类都可能对其所有子类中的代码没有完全可见性,子类可能会一直注意到在超类中发生了什么。因此,我们需要避免这种强而不必要的耦合。
合成如何解决这个问题?
让我们复习一下同样的例子
public class X{
public void do(){
}
}
Public Class Y{
X x = new X();
public void work(){
x.do();
}
}
这里我们在Y类中创建X类的引用,并通过创建X类的实例调用X类的方法。 现在所有的强耦合都消失了。父类和子类现在彼此高度独立。类可以自由地进行更改,这在继承情况下是危险的。
2)第二个非常好的优点是它提供了方法调用的灵活性,例如:
class X implements R
{}
class Y implements R
{}
public class Test{
R r;
}
在测试类中使用r引用,我可以调用X类以及Y类的方法。这种灵活性在继承中是不存在的
3)另一个巨大优势:单元测试
public class X {
public void do(){
}
}
Public Class Y {
X x = new X();
public void work(){
x.do();
}
}
在上面的例子中,如果x实例的状态未知,可以用一些测试数据很容易地模拟出来,所有的方法都可以很容易地测试出来。这在继承中是完全不可能的,因为您严重依赖于超类来获取实例的状态并执行任何方法。
4)我们应该避免继承的另一个很好的理由是Java不支持多重继承。
让我们举个例子来理解这一点:
Public class Transaction {
Banking b;
public static void main(String a[])
{
b = new Deposit();
if(b.deposit()){
b = new Credit();
c.credit();
}
}
}
很高兴知道:
组合在运行时很容易实现,而继承在编译时提供其特性 组合也称为HAS-A关系,继承也称为is - a关系
因此,由于上述各种原因,要养成总是喜欢组合而不是继承的习惯。
Though both Inheritance and Composition provides code reusablility, main difference between Composition and Inheritance in Java is that Composition allows reuse of code without extending it but for Inheritance you must extend the class for any reuse of code or functionality. Another difference which comes from this fact is that by using Composition you can reuse code for even final class which is not extensible but Inheritance cannot reuse code in such cases. Also by using Composition you can reuse code from many classes as they are declared as just a member variable, but with Inheritance you can reuse code form just one class because in Java you can only extend one class, because multiple Inheritance is not supported in Java. You can do this in C++ though because there one class can extend more than one class. BTW, You should always prefer Composition over Inheritance in Java, its not just me but even Joshua Bloch has suggested in his book
推荐文章
- 如何分割逗号分隔的字符串?
- Java字符串—查看字符串是否只包含数字而不包含字母
- Mockito.any()传递带有泛型的接口
- 在IntelliJ 10.5中运行测试时,出现“NoSuchMethodError: org.hamcrest. matcher . descripbemismatch”
- 使用String.split()和多个分隔符
- Java数组有最大大小吗?
- 在Android中将字符串转换为Uri
- 从JSON生成Java类?
- 为什么我不能继承静态类?
- 为什么java.util.Set没有get(int index)?
- 合并两个PHP对象的最佳方法是什么?
- Swing和AWT的区别是什么?
- 为什么Java流是一次性的?
- 四舍五入BigDecimal *总是*有两位小数点后
- 设计模式:工厂vs工厂方法vs抽象工厂