组合和继承是一样的吗? 如果我想实现组合模式,我如何在Java中做到这一点?
当前回答
组合和继承是一样的吗?
它们不一样。
组合:它允许以对象的单个实例的方式处理一组对象。组合的目的是将对象“组合”成树状结构,以表示部分-整体层次结构
继承:类从其所有超类继承字段和方法,无论是直接的还是间接的。子类可以覆盖它继承的方法,也可以隐藏它继承的字段或方法。
如果我想实现组合模式,我如何在Java中做到这一点?
维基百科的文章足以在java中实现复合模式。
主要参与者:
组件:
是所有组件的抽象,包括复合组件吗 声明组合中对象的接口
叶:
表示组合中的叶对象 实现所有组件方法
复合材料:
表示一个复合组件(有子组件) 实现操作子节点的方法 实现所有Component方法,通常是将它们委托给其子方法
理解Composite模式的代码示例:
import java.util.List;
import java.util.ArrayList;
interface Part{
public double getPrice();
public String getName();
}
class Engine implements Part{
String name;
double price;
public Engine(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Trunk implements Part{
String name;
double price;
public Trunk(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Body implements Part{
String name;
double price;
public Body(String name,double price){
this.name = name;
this.price = price;
}
public double getPrice(){
return price;
}
public String getName(){
return name;
}
}
class Car implements Part{
List<Part> parts;
String name;
public Car(String name){
this.name = name;
parts = new ArrayList<Part>();
}
public void addPart(Part part){
parts.add(part);
}
public String getName(){
return name;
}
public String getPartNames(){
StringBuilder sb = new StringBuilder();
for ( Part part: parts){
sb.append(part.getName()).append(" ");
}
return sb.toString();
}
public double getPrice(){
double price = 0;
for ( Part part: parts){
price += part.getPrice();
}
return price;
}
}
public class CompositeDemo{
public static void main(String args[]){
Part engine = new Engine("DiselEngine",15000);
Part trunk = new Trunk("Trunk",10000);
Part body = new Body("Body",12000);
Car car = new Car("Innova");
car.addPart(engine);
car.addPart(trunk);
car.addPart(body);
double price = car.getPrice();
System.out.println("Car name:"+car.getName());
System.out.println("Car parts:"+car.getPartNames());
System.out.println("Car price:"+car.getPrice());
}
}
输出:
Car name:Innova
Car parts:DiselEngine Trunk Body
Car price:37000.0
解释:
Part是一片叶子 汽车包含许多部件 汽车的不同部分已经添加到car中 汽车价格=(各部件价格)之和
关于组合和继承的利弊,请参考下面的问题。
喜欢组合而不是继承?
其他回答
我认为这个例子清楚地解释了继承和组合之间的区别。
在本例中,使用继承和组合解决了这个问题。作者注意到;在继承中,父类的更改可能会导致继承它的派生类出现问题。
在这里,您还可以看到使用UML进行继承或组合时在表示上的区别。
http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should-you-choose-.html
两个类之间的继承,其中一个类扩展了另一个类,建立了“IS A”关系。
另一端的组合包含类中另一个类的实例,建立了“Has A”关系。组合在java中是很有用的,因为它在技术上便于多重继承。
另一个例子,考虑一个汽车类,这将是一个很好的组合使用,一个汽车将“有”一个发动机,一个变速器,轮胎,座位,等等。它不会扩展任何这些类。
它们完全不同。继承是一种“是-是”关系。作文是“has-a”。
通过使用另一个类C的实例作为类的字段来进行组合,而不是扩展C。java.util就是一个很好的例子,其中组合比继承要好得多。堆栈,它目前扩展了java.util.Vector。现在看来,这是一个大错。堆栈“is-NOT-a”向量;不应该允许任意插入和删除元素。应该是合成。
不幸的是,现在纠正这个设计错误已经太晚了,因为现在更改继承层次结构将破坏与现有代码的兼容性。如果Stack使用组合而不是继承,那么它总是可以被修改为使用另一种数据结构,而不会违反API。
我强烈推荐Josh Bloch的《Effective Java第二版》
项目16:比起继承,更喜欢组合 项目17:设计和文件的继承或禁止
好的面向对象设计不是随意扩展现有的类。你的第一直觉应该是作曲。
参见:
组合与继承:两种基本的类关联方法的比较
遗产怎么会是危险的?
让我们举个例子
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关系
因此,由于上述各种原因,要养成总是喜欢组合而不是继承的习惯。
推荐文章
- 如何格式化Joda-Time DateTime仅为mm/dd/yyyy?
- 如何在POM.xml中引用环境变量?
- 如何在android中复制一个文件?
- 将整数转换为字符串,以逗号表示千
- 接口方法的最终参数-有什么意义?
- Java中的@UniqueConstraint注释
- 如何在清洁模式下运行eclipse ?如果我们这样做会发生什么?
- 获取java.lang.ClassNotFoundException: org.apache.commons.logging.LogFactory异常
- Java中的正则表达式命名组
- c#和Java的主要区别是什么?
- 什么是NullPointerException,我如何修复它?
- 在Java中使用“final”修饰符
- 无法在Flutter上找到捆绑的Java版本
- 如何在Kotlin解析JSON ?
- 如何在新的材质主题中改变背面箭头的颜色?