代码之家  ›  专栏  ›  技术社区  ›  gmhk

继承与构成的区别

  •  167
  • gmhk  · 技术社区  · 15 年前

    组成和继承是一样的吗? 如果我想实现构图模式,我如何在Java中实现呢?

    17 回复  |  直到 6 年前
        1
  •  262
  •   polygenelubricants    15 年前

    它们完全不同。继承是一种 “IS-A” 关系。组成是一个 “HAS-A” .

    您通过拥有另一个类的实例来进行组合 C 作为类的字段,而不是扩展 C . 一个很好的例子是,组合比继承要好得多 java.util.Stack ,当前扩展 java.util.Vector . 这现在被认为是一个错误。烟囱 “IS-NOT-A” 向量;不允许随意插入和删除元素。应该是作文。

    不幸的是,纠正这种设计错误为时已晚,因为现在更改继承层次结构将破坏与现有代码的兼容性。 Stack 使用组合而不是继承,可以修改它以使用另一个数据结构,而不违反API .

    我强烈推荐乔希·布洛克的书 有效Java第二版

    • 第16条:有利于组合而非继承
    • 第十七条继承或者禁止继承的设计和文件

    好的面向对象设计并不是要自由地扩展现有的类。你的第一反应应该是作曲。


    参见:

        2
  •  170
  •   Andrea Bergonzo l'L'l    8 年前

    组成方式 HAS A
    继承意味着 IS A

    Example 汽车 有一个 发动机和汽车 是一个 汽车用品

    在编程中,这表示为:

    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.
    }
    
        3
  •  28
  •   Samix    6 年前

    继承会有多危险?

    让我们举个例子

    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;    
    }
    

    在使用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();    
            }
        }
    }
    

    很高兴知道:

    1. 组合在运行时很容易实现,而继承在编译时提供其特性

    2. 组合也被称为有关系,继承也被称为是关系。

    因此,出于以上各种原因,使它成为一种习惯,总是喜欢组合而不是继承。

        4
  •  18
  •   Ravindra babu    8 年前

    @michael rodrigues给出的答案不正确(我很抱歉,我无法直接发表评论),可能会导致一些混乱。

    接口实现 is a form of inheritance …当您实现一个接口时,您不仅继承了所有的常量,还将把对象提交给接口指定的类型;它仍然是一个“ IS-A “关系。如果一辆车 可填充的 “汽车” IS-A 可填充的 ,并且可以在代码中使用 可填充 .

    组合与继承有本质的区别。 当你用作文的时候,你正在(作为另一个答案笔记)做一个“ HAS-A 两个对象之间的关系,而不是 IS-A “使用继承时所建立的关系 .

    所以,从其他问题中的汽车例子来看,如果我想说一辆汽车 有-A “油箱,我将使用以下成分:

    public class Car {
    
    private GasTank myCarsGasTank;
    
    }
    

    希望能消除误解。

        5
  •  14
  •   Samix    6 年前

    继承 带出 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");
      }
    }
    

    如果是为了继承,我们将拥有两种不同的鸟类,它们一遍又一遍地执行飞行功能。所以继承和组成是完全不同的。

        6
  •  7
  •   dlamblin    11 年前

    构图和听起来一样——你通过插入部件来创建一个对象。

    编辑 这个答案的其余部分错误地基于以下前提。
    这是通过接口实现的。
    例如,使用 Car 上面的例子,

    Car implements iDrivable, iUsesFuel, iProtectsOccupants
    Motorbike implements iDrivable, iUsesFuel, iShortcutThroughTraffic
    House implements iProtectsOccupants
    Generator implements iUsesFuel
    

    因此,使用一些标准的理论组件,您可以构建您的对象。然后你的工作就是填写 House 保护其使用者,以及 小型车 保护乘客。

    继承就像另一条路。从一个完整(或半完整)对象开始,替换或重写要更改的各种位。

    例如, MotorVehicle 可能会有一个 Fuelable 方法及 Drive 方法。您可以保留燃油方法,因为加注摩托车和汽车是相同的,但您可以覆盖 驱动器 方法,因为摩托车的驾驶方式与 小型车 .

    有了继承,一些类已经完全实现了,而另一些类则拥有强制重写的方法。在作曲方面,你什么都没有得到。(但是,如果您碰巧有东西在周围,您可以通过在其他类中调用方法来实现接口)。

    组合被认为是更灵活的,因为如果你有一个方法,比如iusesfuel,你可以在其他地方有一个方法(另一个类,另一个项目),它只关心处理可以添加燃料的对象,不管是汽车、船、炉子、烧烤等等。接口要求那些说它们实现了inte的类rface实际上拥有该接口所涉及的方法。例如,

    iFuelable Interface:
       void AddSomeFuel()
       void UseSomeFuel()
       int  percentageFull()
    

    那么你可以在别的地方找个方法

    private void FillHerUp(iFuelable : objectToFill) {
    
       Do while (objectToFill.percentageFull() <= 100)  {
    
            objectToFill.AddSomeFuel();
       }
    

    奇怪的例子,但是它表明这个方法不关心它填充的内容,因为对象实现了 iUsesFuel ,可以填写。故事的结尾。

    如果使用继承,则需要不同的 FillHerUp 处理方法 MotorVehicles Barbecues 除非您有一些相当奇怪的“使用燃料的对象”基对象从中继承。

        7
  •  5
  •   Community CDub    8 年前

    组成和继承是一样的吗?

    它们不一样。

    composition :它使一组对象必须以与单个对象实例相同的方式进行处理。复合的目的是将对象“组合”到树结构中以表示部分整体层次结构

    Inheritation<:a class inherits fields and methods from all its superclasses,which direct or indirect.子类可以重写它继承的方法,也可以隐藏它继承的字段或方法。

    < Buff行情>

    如果我想实现构图模式,我怎样才能在Java中实现呢?

    < /块引用>

    < HRFF=“HTTPS://E.WiKiTo.Org/Wik/CypItEyType”Re=“NoFoLoLoNeFror”>维基百科 文章很好地实现了Java中的复合模式。

    主要参与者:

    组件

    1. 是所有组件的抽象,包括复合组件
    2. 声明组成中对象的接口

    leaf :。

    1. 表示组成中的叶对象
    2. 实现所有组件
      1. 复合材料

        1. 表示复合组件(具有子级的组件)
        2. 实现用于操作子级的方法
        3. 实现所有组件方法,通常通过将它们委托给其子级来实现

        代码示例以了解 composite pattern:。

        import java.util.list;
        导入java.util.arraylist;
        
        接口部分{
        public double getPrice();
        公共字符串getname();
        }
        类引擎实现部分{
        字符串名称;
        双倍价格;
        公共引擎(字符串名称,双价格){
        this.name=名称;
        this.price=价格;
        }
        public double getprice(){
        退货价格;
        }
        公共字符串getname()。{
        返回名称;
        }
        }
        类中继实现部分{
        字符串名称;
        双倍价格;
        公共中继(字符串名称,双价格){
        this.name=名称;
        this.price=价格;
        }
        public double getprice(){
        退货价格;
        }
        公共字符串getname()。{
        返回名称;
        }
        }
        类主体实现部分{
        字符串名称;
        双倍价格;
        公共机构(字符串名称,双价格){
        this.name=名称;
        this.price=价格;
        }
        public double getprice(){
        退货价格;
        }
        公共字符串getname()。{
        返回名称;
        }
        }
        类车实现部分{
        列出<零件>零件;
        字符串名称;
        
        公共车(字符串名称){
        this.name=名称;
        零件=新阵列列表<零件>();
        }
        公共作废添加部分(部分){
        零件。添加(零件);
        }
        公共字符串getname()。{
        返回名称;
        }
        公共字符串getPartNames()。{
        StringBuilder sb=new StringBuilder();
        用于(零件部分:零件){
        sb.append(part.getname()).append(“”);
        }
        返回sb.toString();
        }
        public double getprice(){
        双价=0;
        用于(零件部分:零件){
        price+=part.getPrice();
        }
        退货价格;
        }
        }
        
        公共类复合表达式{
        公共静态void main(字符串args[]){
        部分发动机=新发动机(“diselengine”,15000);
        部分后备箱=新后备箱(“后备箱”,10000);
        零件主体=新主体(“主体”,12000);
        
        汽车=新车(“Innova”);
        汽车.附加部件(发动机);
        汽车。附加部分(后备箱);
        汽车。添加部分(车身);
        
        double price=car.getprice();
        
        system.out.println(“车名:”+car.getname());
        system.out.println(“汽车零件:”+car.getPartNames());
        system.out.println(“汽车价格:”+car.getPrice());
        }
        
        }
        < /代码> 
        
        

        输出:

        car name:innova
        汽车零部件:双行李厢体
        车价:37000.0
        < /代码> 
        
        

        说明:

        1. partis a leaf
        2. carcontains many parts
        3. 不同的汽车已添加到汽车
        4. car的价格=sum of(price of eachpart)

        有关组合和继承的利弊,请参阅下面的问题。

        prefer composition over inheritance?

        :它使一组对象必须以与单个对象实例相同的方式进行处理。组合的目的是将对象“组合”成树结构,以便表示部分整体层次结构

        Inheritance:类从其所有超类继承字段和方法,无论是直接的还是间接的。子类可以重写它继承的方法,也可以隐藏它继承的字段或方法。

        如果我想实现构图模式,我如何在Java中实现呢?

        Wikipedia文章很好地实现了爪哇的复合模式。

        enter image description here

        主要参与者:

        组件以下内容:

        1. 是所有组件的抽象,包括复合组件
        2. 声明中对象的接口作文

        叶子:

        1. 表示中的叶对象作文
        2. 实现一切组件方法

        混合成的:

        1. 表示复合组件(具有子级的组件)
        2. 实现用于操作子级的方法
        3. 实现所有组件方法,通常通过将它们委托给其子级来实现

        要理解的代码示例混合成的模式:

        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
        

        说明:

        1. 部分是一片叶子
        2. 小型车包含多个部分
        3. 不同部分车的已添加到车中
        4. 价格小型车=总价格部分)

        关于组合和继承的利弊,请参阅下面的问题。

        Prefer composition over inheritance?

        8
  •  4
  •   BlackICE    15 年前

    作为另一个例子,考虑一个汽车类,这将是一个很好的组合使用,一辆汽车将“有”一个发动机,一个变速器,轮胎,座椅等。它不会扩展任何这些类。

        9
  •  3
  •   Ravindra babu    8 年前

    遗传 在两个类之间,一个类扩展另一个类 是一个 “关系”。

    作文 另一端包含类中另一个类的实例 有一个 “关系”。 作文 Java是有用的,因为它在技术上促进了多重继承。

        10
  •  3
  •   Keshav Gera    8 年前

    简单来说,聚合意味着有一种关系。

    组合是聚合的一种特殊情况 . 以一种更具体的方式,一个受限制的聚合称为组合。当一个对象包含另一个对象时,如果所包含的对象不存在容器对象,则称为组合。 例如:一个班级包含学生。没有班级学生是不可能存在的。学生和学生之间有作文。

    为什么使用聚合

    代码可重用性

    使用聚合时

    当没有关系时,代码重用也最好通过聚合来实现。

    遗传

    继承是父子关系继承意味着是一种关系

    Java中的继承是一个对象获取父对象的所有属性和行为的机制。

    在Java中使用继承 1代码可重用性。 2在子类中添加额外的特性以及方法重写(这样就可以实现运行时多态性)。

        11
  •  2
  •   Robert    10 年前

    构图是指某物由不同的部分组成,它与这些部分有着很强的关系。如果主体死亡,其他人也一样,他们就不能拥有自己的生命。人体就是一个粗略的例子。把心脏拿出来,其他的部分都消失了。

    继承就是你获取已经存在的东西并使用它的地方。没有牢固的关系。一个人可以继承他父亲的遗产,但他可以不继承。

    我不知道Java,所以我不能提供一个例子,但我可以提供一个概念的解释。

        12
  •  2
  •   Nitin Pawar    10 年前

    虽然继承和组合都提供代码可重用性,但Java中的组成和继承的主要区别在于,构图允许在不扩展代码的情况下重用代码,但是对于继承,必须扩展类以重用代码或功能。这一事实的另一个区别是,通过使用组合,您可以重用代码,即使是不可扩展但继承在这种情况下也不能重用代码的最终类。此外,通过使用组合,您可以重用许多类中的代码,因为它们被声明为一个成员变量,但是继承可以重用一个类的代码形式,因为在爪哇中只能扩展一个类,因为Java中不支持多重继承。你可以在C++中这样做,因为有一个类可以扩展不止一个类。顺便说一句,你应该 在Java中更喜欢组合而不是继承 不仅是我,甚至 约书亚·布洛克 在他的书中有建议

        13
  •  1
  •   Ravindra babu    8 年前

    我认为这个例子清楚地解释了 遗传 作文 .

    在这个例子中,使用继承和组合解决了这个问题。作者注意到这样一个事实:在 继承 超类中的更改可能会导致继承它的派生类出现问题。

    在那里,当您使用UML进行继承或组合时,您还可以看到表示上的差异。

    http://www.javaworld.com/article/2076814/core-java/inheritance-versus-composition--which-one-should-you-choose-.html

        14
  •  1
  •   Sheo Dayal Singh    8 年前

    继承与组合。

    继承和组合都用于类行为的可重用性和扩展。

    继承主要用于族算法编程模型中,如IS-A关系型表示类似的对象。例子。

    1. 除尘器是一辆小汽车
    2. 游猎是一辆车

    这些是汽车家族的。

    构图表示has-a关系类型。它表示一个对象的能力,如duster有五个齿轮,safari有四个齿轮等。每当我们需要扩展现有类的能力时,就使用构图。 例子 我们需要在除尘器对象中再添加一个齿轮,然后再创建一个齿轮对象并将其组合到除尘器对象中。

    除非所有派生类都需要这些功能,否则我们不应该在基类中进行更改。对于这种情况,我们应该使用组合。例如

    由B类派生的A类

    类C派生的类A

    类D派生的类A。

    当我们在A类中添加任何功能时,即使C类和D类不需要这些功能,它也可用于所有子类。对于这种情况,我们需要为这些功能创建一个单独的类,并将其组合到所需的类(这里是B类)。

    示例如下:

              // This is a base class
                     public abstract class Car
                        {
                           //Define prototype
                           public abstract void color();
                           public void Gear() {
                               Console.WriteLine("Car has a four Gear");
                           }
                        }
    
    
               // Here is the use of inheritence
               // This Desire class have four gears.
              //  But we need to add one more gear that is Neutral gear.
    
              public class Desire : Car
                       {
                           Neutral obj = null;
                           public Desire()
                           {
         // Here we are incorporating neutral gear(It is the use of composition). 
         // Now this class would have five gear. 
    
                               obj = new Neutral();
                               obj.NeutralGear();
                           }
    
                           public override void color()
                           {
                               Console.WriteLine("This is a white color car");
                           }
    
                       }
    
    
                 // This Safari class have four gears and it is not required the neutral
                 //  gear and hence we don't need to compose here.
    
                       public class Safari :Car{
                           public Safari()
                           { }
    
                           public override void color()
                           {
                               Console.WriteLine("This is a red color car");
                           }
    
    
                       }
    
       // This class represents the neutral gear and it would be used as a composition.
    
       public class Neutral {
                          public void NeutralGear() {
                               Console.WriteLine("This is a Neutral Gear");
                           }
                       }
    
        15
  •  0
  •   HM Nayem    8 年前

    组合意味着创建一个与特定类相关的类的对象。 假设学生与会计有关系;

    继承是,这是具有扩展功能的前一个类。这意味着这个新类是具有一些扩展特性的旧类。 假设学生是学生,但所有学生都是人。因此,学生和人之间存在着一种关系。这是遗产。

        16
  •  0
  •   Ranga Reddy    7 年前

    不,两者都不同。组合跟随“有-有”关系和继承跟随“是-一”关系。构图最好的例子是战略模式。

        17
  •  0
  •   Vikas Kapadiya    7 年前

    继承意味着重用一个类的完整功能,在这里,我的类必须使用超级类的所有方法,我的类将与超级类紧密耦合,如果继承,代码将在两个类中复制。

    但当我们用作文和另一个班级交谈时,我们可以克服所有这些问题。构图正在将另一个类的属性声明到我们要讨论的类中。以及使用该属性可以从类中获得什么功能。

    推荐文章