组合和继承是一样的吗? 如果我想实现组合模式,我应该如何在Java中实现?
组合和继承是一样的吗? 如果我想实现组合模式,我应该如何在Java中实现?
另请参阅:
组合意味着HAS A
继承意味着IS A
例子
: 汽车有一个引擎并且汽车是一种汽车类
在编程中,这表示为:
class Engine {} // The Engine class.
class Automobile {} // Automobile class which is parent to Car class.
class Car extends Automobile { // Car is an Automobile, so Car class extends Automobile class.
private Engine engine; // Car has an Engine so, Car class has an instance of Engine class as its member.
}
继承如何存在风险?
我们来举个例子
public class X{
public void do(){
}
}
Public Class Y extends X{
public void work(){
do();
}
}
1)如上所示,类Y与类X之间的耦合度非常强。如果超类X中有任何变化,Y可能会出现严重故障。假设未来类X实现了一个带有以下签名的方法:
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;
}
在Test类中使用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关系
因此,出于上述各种原因,请始终优先考虑组合而不是继承。
@Michael Rodrigues所给出的答案不正确(我很抱歉;我无法直接评论),可能会引起一些混淆。
接口实现是继承的一种形式...当您实现一个接口时,您不仅继承了所有常量,而且还使您的对象成为接口指定类型的对象;这仍然是一个"is-a"关系。如果汽车实现Fillable,那么汽车"是一个"Fillable,可以在您需要使用Fillable的任何地方使用它。
组合与继承根本不同。当您使用组合时,您(如其他答案中所述)在两个对象之间建立了一个"has-a"关系,与使用继承时建立的"is-a"关系截然不同。
因此,在其他问题的汽车示例中,如果我想说汽车"有"油箱,我将使用组合,如下所示:
public class Car {
private GasTank myCarsGasTank;
}
希望这能消除任何误解。
继承 显现出 IS-A 关系。 组合 显现出 HAS-A 关系。
策略模式说明在定义特定行为的算法族存在的情况下应该使用组合。
一个经典的例子是一个鸭子类,它实现了一种飞行行为。
public interface Flyable{
public void fly();
}
public class Duck {
Flyable fly;
public Duck(){
fly = new BackwardFlying();
}
}
因此,我们可以有多个实现飞行的类,例如:
public class BackwardFlying implements Flyable{
public void fly(){
Systemout.println("Flies backward ");
}
}
public class FastFlying implements Flyable{
public void fly(){
Systemout.println("Flies 100 miles/sec");
}
}
如果只是使用继承,我们将不得不拥有实现飞行功能的两个不同鸟类。因此,继承和组合是完全不同的。
Car implements iDrivable, iUsesFuel, iProtectsOccupants
Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
House implements iProtectsOccupants
Generator implements iUsesFuel
iFuelable Interface:
void AddSomeFuel()
void UseSomeFuel()
int percentageFull()
private void FillHerUp(iFuelable : objectToFill) {
Do while (objectToFill.percentageFull() <= 100) {
objectToFill.AddSomeFuel();
}
这是一个奇怪的例子,但它展示了这种方法不关心它正在填充什么,因为对象实现了iUsesFuel接口,所以可以进行填充。故事结束。
如果您使用继承,您将需要不同的FillHerUp
方法来处理MotorVehicles
和Barbecues
,除非您有一些相当奇怪的“ObjectThatUsesFuel”基对象可以继承。
ThisCase
写法,而不是camelCase
。因此最好将您的接口命名为IDrivable
等。如果您正确地将所有接口分组到一个包中,则可能不需要"I"。 - ThePyroEagle组合和继承是一样的吗?
它们不一样。
组合(来自维基百科):它使得一组对象可以被视为单个对象的方式进行处理。组合的目的是将对象组成树形结构,以表示部分-整体层次结构。
继承(来自Oracle文档):一个类从其所有超类(直接或间接)继承字段和方法。子类可以覆盖它继承的方法,或者隐藏它继承的字段或方法。
如果我想实现组合模式,我该如何在Java中实现?
关键参与者:(根据维基百科链接中显示的UML图)
Component:
Leaf:
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
说明:
请参考下面的问题,了解组合和继承的利弊。
简单来说,聚合意味着有一种关系..
组合是聚合的一种特殊情况。更具体地说,受限制的聚合被称为组合。当一个对象包含另一个对象时,如果所包含的对象不能存在于没有容器对象的情况下,则称其为组合。 例如:一个班级包含学生。学生没有班级就无法存在。班级和学生之间存在组合关系。
为什么使用聚合
代码可重用性
何时使用聚合
当不存在“is a”关系时,通过聚合实现最佳代码重用。
继承
继承是父子关系,继承意味着“is a”关系
在Java中,继承是一种机制,其中一个对象获取父对象的所有属性和行为。
在Java中使用继承: 1. 代码可重用性。 2. 在子类中添加额外功能以及方法覆盖(因此可以实现运行时多态性)。
组合是指某物由不同的部分组成,并且与这些部分之间有着紧密的关系。如果主要部分死亡,其他部分也会随之死亡,它们不能独立存在。一个简单的例子就是人体。取出心脏,所有其他部分都会消失。
继承是指你只需要使用已经存在的东西,而没有强烈的关系。一个人可以继承他父亲的财产,但他也可以没有它。
我不懂Java,所以无法提供示例,但我可以解释这些概念。