精华内容
下载资源
问答
  • 组合与继承

    热门讨论 2015-10-04 21:13:25
    组合继承,都是在新类中直接复用旧类的方法,实现系统功能重用。但是各有不同的特点。继承会破坏封装。组合能提供更好的封装性。各有优缺点,总得来说,多用组合,少用继承继承:  子类扩展父类,继承父类的...

        组合和继承,都是在新类中直接复用旧类的方法,实现系统功能重用。但是各有不同的特点。继承会破坏封装。组合能提供更好的封装性。各有优缺点,总得来说,多用组合,少用继承。

    继承:

        子类扩展父类,继承父类的字段和方法,如果访问权限允许,子类可以直接访问父类的字段和方法,很方便,但也破坏了父类的封装性。每个类都应该封装内部信息和实现,只暴漏必要的方法给其他类使用。但继承子类可以直接访问父类内部信息。


        保证父类良好封装性的设计原则

            1.尽量隐藏父类内部数据

            2.不要让子类可以随意访问,修改父类方法

                Private:子类无法访问

                Protected:非子类不能自由访问

                Final:子类不能重写

             3.尽量不要在父类的构造器中调用将要被子类重写的方法


        何时从父类派生新的子类:

             1.子类需要额外增加属性,而不仅仅是属性值的改变。

             2.子类需要增加自己独特的行为方式。


        继承是在编译时刻静态定义的,即是静态复用


    组合:

        该类当成另一个类的组合成分,允许新类直接复用该类的Public方法。


        组合把旧类对象作为新类的Field嵌入,实现新类的功能,用户看到的是新类的方法。新类中使用private修饰嵌入的旧类对象。


        组合是在运行时才确定的,增加了程序的灵活性。



    用EA生成的代码框架

    public class Animal {
    
    	public Animal(){}
    	
    	private void beat(){}
    
    	public void breath(){}
    }
    
    public class Bird 
    {
    	<strong>public Animal m_Animal;</strong>
    
    	public Bird(){}
    
    	public void breath(){}
    
    	public void fly(){}
    }
    
    public class Wolf 
    {
    	<strong>public Animal m_Animal;</strong>
    
    	public Wolf(){}
    
    	public void breath(){}
    
    	public void run(){}
    }

    完善代码:
    class Animal
    {
    	private void beat()
    	{
    		System.out.println("心脏跳动。。。");
    		
    	}
    	public void breath()
    	{
    		beat();
    		System.out.println("吸一口气,吐一口气,呼吸中");
    		
    	}
    }
    
    class Bird
    {
    	//原来父类嵌入子类,作为子类的组合成分;
    	private Animal a;
    	public Bird(Animal a)
    	{
    		this.a=a;
    		
    	}	
    	//定义自己的breath方法;
    	public void breath()
    	{
    		//直接复用父类的Breath来实现子类的Breath;
    		a.breath();	
    	}
    	public void fly()
    	{
    		System.out.println("我在天空自在的飞翔");
    		
    	}
    }
    class Wolf
    {
    	//原来父类嵌入子类,作为子类的组合成分;
    	private Animal a;
    	public Wolf(Animal a)
    	{
    		this.a=a;
    		
    	}	
    	//定义自己的breath方法;
    	public void breath()
    	{
    		//直接复用父类的Breath来实现子类的Breath;
    		a.breath();	
    	}
    	public void run()
    	{
    		System.out.println("我在陆地上快速奔跑");
    	}
    }
    
    
    public class CompositeTest {
    	public static void main(String[] args)
    	{
    		//显示创建嵌入的对象
    		Animal a1 = new Animal ();
    		Bird b = new Bird(a1);
    		b.breath();
    		b.fly();
    		//显示创建嵌入的对象		
    		Animal a2 = new Animal();
    		Wolf w = new Wolf(a2);
    		w.breath();
    		w.run();
    		
    	}
    
    }
    运行结果:


    总结:

           多用组合,少用继承。组合将对象作为新类的Field,运行时创建对象,增加程序的灵活性,但是整体类创建时,需要创建所有的局部对象。继承让子类很便捷的拥有父类的信息,破坏了父类的封装性。组合和继承各有优缺点,在实际开发中应落实实际情况,发展的眼光,选择相对合适的。

    展开全文
  • 组合继承都允许在新的类中放置子对象,组合是显示的这样做,而继承则是隐式的做。  组合技术通常用于想在新类中使用现有类的功能而非他的接口。在新类中嵌入某个对象,让其实现所需要的功能,但新类的用户看到的...
  • 两种代码重用机制——组合与继承

    千次阅读 2016-08-10 10:27:27
    java两种代码重用机制——组合与继承


    1.组合(composition):将某现有类的对象的引用置于新类之中,作为新类的成员。成员间是"has-a"的关系。这样做的好处是可以利用自己或别人已调试好的代码,提高编程效率。

    2.继承(inheritance):java中所有类都默认继承Object类。在新类后用extends关键字后跟继承的基类的方式实现。(继承的类称为子类)子类初始化前先对父类进行初始化。基类构造器为有参构造器时,需使用super关键字显示调用基类构造器并配以适当的参数列表。另外,如果在基类中有有参构造器而没有显示编写无参构造器,在子类中编写无参构造器且没有使用super显示调用基类构造器,则会产生异常。在访问权限足够的情况下(子类不能访问父类private权限的方法或成员),子类中可以使用super关键字调用从基类继承来的的方法,子类重写父类方法时,方法的参数和修饰词都应相同,当然子类也可以有自己的方法。、

    继承的优点之一是它支持增量开发,允许你引入新代码而不会在现有代码中引发Bug。继承描述了新类与基类之间的关系,即”新类是基类的一种类型“,这意味着基类中所有的方法在导出类中同样有效,导出类对象也是一种类型的基类对象(”即向上转型“)。一般在需要用到向上转型时才使用继承这一技术。

    子类:

    public class Test01 extends Test1{
    	Test01(){
    		System.out.println("hello01");
    		
    	}
    	protected void m1(){
    		super.m1();
    	}
    	public  static void main(String[] Args){
    		Test01 t = new Test01();
    		t.m1();
    	}
    }
    基类:
    public class Test1 {
    	Test1(){
    		this("lei");
    		System.out.println("hello");
    		
    	}
    	Test1(String s){
    		System.out.println("hello"+s);
    	}
    	//
    	protected void m1(){
    		
    		System.out.println("method1");
    		m2();
    		this.m2();
    	}
    	void m2(){
    		System.out.println("method2");
    	}
    	void m3(){
    		System.out.println("i:"+i+"; "+"s:"+s);
    	}
    }


    展开全文
  • Java中组合与继承都可以实现代码的复用,甚至可以相互替换。但仅从语言的逻辑上看,继承(extend)更应该用于包含关系(sth is a sth_baby),而组合可以是并列或者说共有的关系(sth has a sth_baby)。组合实现:...

    Java中组合与继承都可以实现代码的复用,甚至可以相互替换。但仅从语言的逻辑上看,继承(extend)更应该用于包含关系(sth is a sth_baby),而组合可以是并列或者说共有的关系(sth has a sth_baby)。


    组合实现:

    package cn.LYZ.oop;
    
    public class Animal2 {
    	String eye;
    	
    	public void run2(){
    		System.out.println("runrun2");
    	}
    	public void eat2(){
    		System.out.println("eateat2");
    	}
    	public void sleep2(){
    		System.out.println("zzzzzzzz2");
    	}
    	
    	public Animal2(){
    		//super();
    		System.out.println("creat an animal2");
    	}
    	
    	public static void main(String[] args){
    		Bird2 b = new Bird2();
    		b.run2();
    		b.animal2.eat2();
    	}
    
    }
    
    class Mammal2 {
    	Animal2 animal2 = new Animal2();
    	public void taisheng2(){
    		System.out.println("taisheng2");
    	}
    }
    
    class Bird2 {
    	Animal2 animal2 = new Animal2();
    	
    	public void run2(){
    		animal2.run2();
    		//super.run();
    		System.out.println("little bird2");
    	}
    	
    	public void eggsheng2(){
    		System.out.println("luansheng2");
    	}
    	
    	public Bird2(){
    		//super();
    		System.out.println("creat a bird2");
    	}
    }

    继承实现:

    public class Animal {
    	String eye;
    	
    	public void run(){
    		System.out.println("runrun");
    	}
    	public void eat(){
    		System.out.println("eateat");
    	}
    	public void sleep(){
    		System.out.println("zzzzzzzz");
    	}
    	
    	public Animal(){
    		//super();
    		System.out.println("creat an animal");
    	}
    
    }
    
    class Mammal extends Animal{
    	public void taisheng(){
    		System.out.println("taisheng");
    	}
    }
    
    class Bird extends Animal{
    	public void run(){
    		//super.run();
    		System.out.println("little bird");
    	}
    	
    	public void eggsheng(){
    		System.out.println("luansheng");
    	}
    	
    	public Bird(){
    		//super();
    		System.out.println("creat a bird");
    	}
    }
    

    展开全文
  • 类的组合与继承

    2017-02-09 18:19:56
    在“对象类”那篇博客中,我们定义了两个类,一个是...类类之间有一种父子的关系,子类继承父类的属性和方法,称为继承。在继承里,子类拥有父类的方法和属性,同事子类也可以有自己的方法和属性。 我们把那一

    在“对象与类”那篇博客中,我们定义了两个类,一个是person,一个是family;在family类中创建person类中的对象,把这个对象视为family类的一个属性,并调用它的方法处理问题,这种复用方法叫“组合”。还有一种复用方式,就是继承。

    类与类之间有一种父与子的关系,子类继承父类的属性和方法,称为继承。在继承里,子类拥有父类的方法和属性,同事子类也可以有自己的方法和属性。

    我们把那一篇博客中的组合代码用继承来实现,代码如下:

    <?php
    /**
     * Created by PhpStorm.
     * User: lightWay
     * Date: 2017/2/9
     * Time: 18:24
     */
    class Person
    {
        public $name = 'Tom';
        public $gender;
        static $money = 10000;
    
        public function __construct()
        {
            echo '这就是父类',PHP_EOL;
        }
    
        public function say()
        {
            echo $this->name,"\tis",$this->gender,"\r\n";
        }
    }
    
    class Family extends Person
    {
        public $name;
        public $gender;
        public $age;
        static $money = 100000;
    
        public function __construct()
        {
            parent::__construct(); //调用父类的构造方法
            echo '这里是子类',PHP_EOL;
        }
    
        public function say()
        {
            parent::say();
            echo $this->name,"\tis\t",$this->gender,"and is\t",$this->age,PHP_EOL;
        }
    
        public function cry()
        {
            echo parent::$money,PHP_EOL;
            echo '%>_<%',PHP_EOL;
            echo self::$money,PHP_EOL;
            echo '(*^_^*)';
        }
    }
    
    $poor = new Family();
    $poor->name = 'Lee';
    $poor->gender = 'female';
    $poor->age = 25;
    $poor->say();
    $poor->cry();
    运行上面的代码,可以得到如下图所示的结果:



    从上面代码中可以了解继承的实现。在继承中,用parent指代父类,用self指代自身。使用 “::” 运算符(范围解析操作符)调用父类的方法。“::” 操作符还用来作为类常量和静态方法的调用,不要把这两种应用混淆。

    既然提到了静态,就需要强调一点,如果声明类成员或方法为static,就可以不实例化类而直接访问,同时也就不能通过一个对象访问其中的静态成员(静态方法除外),也不能用 “::” 访问一个非静态方法。比如,把上例中的$poor->cry();换成$poor::cry(),按照这个规律,应该是要报错的。可能试验时,并没有报错,而且能够正确输出。这是因为用“::”方式调用一个非静态方法会导致一个E_STRICT级别的错误,而这里的PHP设置默认没有开启这个级别的报错提示。打开PHP安装目录下的php.ini文件,设置如下:

    error_reporting = E_ALL|E_STRICT
    display_errors = On
    再次运行,就会看到错误提示。因此,用 “::” 访问一个非静态方法不符合语法,但PHP仍然能够正确地执行代码,这只是PHP所做的一个“兼容”或者说“让步”。 在开发时,设置最严格的报错等级,在部署时可适当调低

    组合与继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义识别类之间的组合关系和继承关系。比如,通过一些总结,得出了继承是一种“是、像”的关系,而组合是一种 “需要” 的关系。利用这条规律,就可以很简单地判断出父亲与儿子应该是继承关系,父亲与家庭应该是组合关系。还可以从另外一个角度看,组合偏重于整体与局部的关系,而继承偏重于父与子的关系,如下图所示:

    从方法复用角度考虑,如果两个类具有很多相同的代码和方法,可以从这两个类中抽象出一个父类,提供公共方法,然后两个类作为子类,提供个性方法。这时用继承语意更好。继承的UML图如下图所示:


    而组合就没有这么多限制。组合之间的类关系(体现为复用代码)很小,甚至没有关系,如下图所示:


    然而在编程中,继承与组合的取舍旺旺并不是这么直接明了,很难说说二者是“像”的关系还是“需要”的关系,甚至把它拿到现实世界中建模,还是无法决定应该是继承还是组合。那应该怎么办呢?有什么标准码?的确有,这个标准就是“低耦合”。

    耦合是一个软件结构内不同模块之间互连程度的度量,也就是不同模块之间的依赖关系。

    低耦合指模块与模块之间,尽可能地使模块之间独立存在;模块与模块之间的接口尽量少而简单。现代的面向对象的思想不强调为真实世界建模,变得更理性化一些,把目标放到解耦上。

    解耦是要解除模块与模块之间的依赖。

    按照这个思想,继承与组合二者语义上难以区分,在二者均可使用的情况下,更倾向于使用组合。为什么呢?继承存在什么问题呢?

    1. 继承破坏封装性。

      比如,定义鸟类为父类,具有羽毛属性和飞翔方法,其子类天鹅、鸭子、鸵鸟等继承鸟这个类。显然,鸭子和鸵鸟不需要飞翔这个方法,但作为子类,他们却可以无区别地使用飞翔这个方法,显然破坏了类的封装性。而组合,从语义上来说,要优于继承。

    2. 继承是紧耦合的。

      继承使得子类和父类捆绑在一起。组合仅通过唯一接口和外部进行通信,耦合度要低于继承。

    3. 继承扩展复杂

      随着继承层数的增加和子类的增加,讲涉及及大量方法重写。使用组合,可以根据类型约束,实现动态组合,减少代码。

    4. 不恰当地使用继承可能违反现实世界中的逻辑。

      比如,人作为父类,雇员、经理、学生作为子类,可能存在这样的问题,经理一定是雇员,学生也可能是雇员,而使用继承的话,一个人就无法拥有多个角色。这种问题归结起来就是“角色”和“权限”问题。在权限系统中很可能存在这样的问题,经理权利和职位大于主管,但出于分工和安全的考虑,经理没有权限直接操作主管所负责的资源,技术部经理也没权限直接命令市场部主管。这就要求角色和权限几桶的设计要更灵活。不恰当的继承可能导致逻辑混乱,而使用组合就可以较好地解决这个问题。

    当然,组合并非没有缺点。在创建组合对象时,组合需要一一创建局部对象,这一定程度上增加了一些代码,而继承则不需要这一步,因为子类自动有了父类的方法,代码如下所示:

    <?php
    /**
     * Created by PhpStorm.
     * User: lightWay
     * Date: 2017/2/10
     * Time: 16:16
     */
    class Car
    {
        public function addoil()
        {
            echo "Add oil \r\n";
        }
    }
    
    //继承实现
    class Bmw extends Car
    {
    
    }
    
    //组合实现
    class Benz
    {
        public $car;
    
        public function __construct()
        {
            $this->car = new Car();
        }
    
        public function addoil()
        {
            $this->car->addoil();
        }
    }
    
    $bmw = new Bmw();
    $bmw->addoil();
    $benz = new benz();
    $benz->addoil();
    
    

    显然,组合比继承增加了代码量。组合还有其他的一些缺点,不过总体来说,是优点大于缺点。

    继承最大的有点事扩展简单,但是其缺点大于优点,所以在设计时,需要慎重考虑。那应该如何使用继承呢?

    • 精心设计专门用于被继承的类,继承树的抽象层应该比较稳定,一般不要多于三层。
    • 对于不是专门用于被继承的类,禁止其被继承,也就是使用final修饰符。使用final修饰符既可以防止重要方法被非法覆写,又能给编辑器寻找优化的机会。
    • 优先考虑用组合关系提高代码的可重用性。
    • 子类是一种特殊的类型,而不只是父类的一个角色。
    • 子类扩展,而不是覆盖或者使父类的功能失效。
    • 底层代码多用组合,顶层/业务层代码多用继承。底层用组合可以提高效率,避免臃肿。顶层代码用继承可以提高灵活性,让业务使用更方便。
    继承并非一无是处,而组合也不是完美无缺的。如果既要组合的灵活,又要继承的简洁,可以做到吗?

    当然可以,譬如多重继承,就具有这个特性。多重继承里一个类可以同时继承多个父类,组合两个父类的功能。C++里就是使用的这种模型来增强继承的灵活性的,但是多重继承过于灵活,并且会带来“菱形问题”,故为其使用带来了不少困难,模型变得复杂起来,因此在大多数语言中,都放弃了多重继承这一模型。

    多重继承太复杂,那么还有其他方式能比较好地解决这个问题吗?PHP5.4引入的新的语法结构Traits就是一种很好的解决方案。Traits的思想来源于C++和Ruby里的Mixin以及Seala里的Traits,可以方便我们实现对象的扩展,是除extend、implement外的另外一种扩展对象的方式。Traits既可以使单继承模式的语言获得多重继承的灵活,又可以避免多重继承带来的种种问题。

    展开全文
  • 再论组合与继承

    万次阅读 2009-03-08 15:50:00
    组合与继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义来识别类之间的组合关系和继承关系。在有些情况下,采用组合关系或者继承关系能完成同样的任务,组合继承存在着对应关系:组合中的整体类和...
  • 组合与继承都能够提高代码的重用性,那么问题来了,组合与继承的区别是什么?什么时候用组合,什么时候用继承?下面是我百度到的,仅供参考: 类的组合继承一样,是软件重用的重要方式。组合继承都是有效地...
  • Java组合与继承

    千次阅读 2018-11-21 21:30:36
    由于新的类是由现有类的对象所组成,所以这种方法称为组合。该方法只是复用了现有程序代码的功能,而非它的形式。 2.按照现有的类型来创建新类。无需改变现有类的形式,采用其形式并在其中添加新代码。这种神奇的...
  • 组合与继承之间的选择

    千次阅读 2013-07-25 16:24:25
    组合继承是允许在新建的类中放入子对象,组合是显示的这样做的,而继承是隐式的做。二者是之间有何区别?或者怎样在二者之间做出选择呢?下面就一起来看看, 组合一般是将现有的类型作为新类型底层实现的一部分...
  • 组合与继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义来识别类之间的组合关系和继承关系。在有些情况下,采用组合关系或者继承关系能完成同样的任务,组合继承存在着对应关系:组合中的整体类和...
  • 组合继承是面向对象中两种代码复用的方式。组合是指在新类里面创建原有类的对象,重复利用已有类的功能。继承是面向对象的主要特性之一,它允许设计人员根据其它类的实现来定义一个类的实现。 组合继承都允许...
  • [Java] 组合与继承的区别

    千次阅读 2016-04-06 21:46:36
    组合继承都允许在新的类中放置子对象,组合是显式地这样做,而继承是隐式地做。 那两者之间的区别是怎样的呢?又该如何选择呢? 很多人对组合理解地还不是很好,所以我们先来理解一下组合组合技术通常用于想...
  • 设计模式推演——组合与继承

    千次阅读 2013-05-05 23:24:15
    OO中,复用代码可以有组合继承两种方式,正如广大人民群众所论述的,尽可能使用组合。 这里我再不厌其烦的说明一下理由: 1. 组合继承在框架结构上要简单,不会造成过深的继承层次。 2. 组合是黑盒重用,...
  • Java学习笔记(二)--组合与继承

    万次阅读 多人点赞 2018-03-05 15:08:05
    继承是面向对象的三大特征之一,也是实现软件复用的重要手段,Java的继承具有单继承的特点,每个类只有一个直接父类,可以有多个间接父类。继承是一种"is-a"的关系。 继承 有开发经验的人都知道继承该怎么写,我就...
  • 目录 目录 前言 组合 派生 ...我们定义一个类是希望能够把类当成模块来...组合: 就是将不同的类混合并加入到其他类中, 来 增加类的功能 / 提高代码的重用性 / 易于维护(对类的修改会直接反应到整个应用中) . 我们可以
  •  由现有的类生成新的类,有两种方法就是组合与继承。我们把UML中的关联关系和聚集关系统称为组合关系。组合与继承都是提高代码可重用性的手段。在设计对象模型时,可以按照语义来识别类之间的组合关系和继承关系。...
  • 组合继承是面向对象中两种代码复用的方式。组合是指在新类里面创建原有类的对象,重复利用已有类的功能。继承是面向对象的主要特性之一,它允许设计人员根据其它类的实现来定义一个类的实现。组合继承都允许在新...
  • java复用类的两种方式-组合与继承

    千次阅读 2018-03-28 19:02:18
    一.组合的概念 在新类里简单地创建... 组合也就是一个类的对象是另外一个类的成员,一般的程序都有组合的意味,只不过是基本数据类型是成员变量。 例如:class Battery { private double power = 0.0; public ...
  • Java 代码复用(组合与继承)

    千次阅读 2013-10-04 10:53:09
    java中的类都是围绕着类进行的。可以通过创建新类来复用代码,而不必从头编写。可以使用别人已经开发并调试...由于新类是由现有类的对象所组成的,所以这种方式称为组合。该方式只是复用了现有程序的代码,而并非它的形

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 332,420
精华内容 132,968
关键字:

组合与继承