zoukankan      html  css  js  c++  java
  • 继承和组合

    继承和组合都可以实现复用的目的,要根据现实意义来区分用哪一种,就像接口和抽象类的区别,其实这两种方式的开销是差不多的,举个列子如下(摘自《疯狂java讲义》):

      ①继承方式

    package 疯狂java讲义;
    
    public class InheritTest {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Bird bird = new Bird();
            bird.breath();
            bird.fly();
            Wolf wolf = new Wolf();
            wolf.breath();
            wolf.run();
        }
    
    }
    
    class Animal{
        private void beat(){
            System.out.println("心脏跳动");
        }
        public void breath(){
            beat();
            System.out.println("呼吸……");
        }
    }
    
    class Bird extends Animal{
        public void fly(){
            System.out.println("鸟会飞行……");
        }
    }
    
    class Wolf extends Animal{
        public void run(){
            System.out.println("狐狸会跑……");
        }
    }

      ②组合方式

    package 疯狂java讲义;
    
    public class CompositeTest {
    
        public static void main(String[] args) {
            // TODO Auto-generated method stub
            Animal1 a1 = new Animal1();
            Bird2 bird = new Bird2(a1);
            Wolf2 wolf = new Wolf2(a1);
            bird.Breath();
            bird.fly();
            wolf.Breath();
            wolf.run();
        }
    
    }
    class Animal1{
        private void beat(){
            System.out.println("心脏跳动");
        }
        public void breath(){
            beat();
            System.out.println("呼吸……");
        }
    }
    
    class Bird2{
        private Animal1 a;
        public Bird2(Animal1 a){
            this.a = a;
        }
        public void Breath(){
            this.a.breath();
        }
        public void fly(){
            System.out.println("鸟会飞行……");
        }
    }
    
    class Wolf2{
        private Animal1 a;
        public Wolf2(Animal1 a){
            this.a = a;
        }
        public void Breath(){
            this.a.breath();
        }
        public void run(){
            System.out.println("狐狸会跑……");
        }
    }

      两种方式达到的效果是一致的。但是对于例子中的情况来说是应该用继承的方式的。因为理解应该是:鸟和狐狸是动物的一种,并非说鸟和狐狸是由动物组成的。如果一个人由手,脚,头,身体组成的,这时候就应该使用组合的方式,可以定义五个类,class 人里面是由class 手,class 脚, class 头,class 身体组合而成。继承是is-a的思想,组合是has-a的思想。

      另外,想实现以上的功能,其实也可以不用继承,也不用组合方式,如下:

    package 疯狂java讲义;
    
    public class CommonTest {
    
        public static void main(String[] args) {
            Animal3 a = new Animal3();
            Bird3 bird = new Bird3();
            Wolf3 wolf = new Wolf3();
            bird.Breath(a);
            bird.fly();
            wolf.Breath(a);
            wolf.run();
    
        }
    }
    
    class Animal3{
        private void beat(){
            System.out.println("心脏跳动");
        }
        public void breath(){
            beat();
            System.out.println("呼吸……");
        }
    }
    class Bird3{ 
        public void Breath(Animal3 a){
            a.breath();
        }
        public void fly(){
            System.out.println("鸟会飞行……");
        }
    }
    
    class Wolf3{ 
        public void Breath(Animal3 a){
            a.breath();
        }
        public void run(){
            System.out.println("狐狸会跑……");
        }
    }

      那当这几种方法如何取舍呢?其实这就是考究一个人的面向对象的思想,要站在思想的高度去理解问题的本质。如果是继承关系的就用继承,如果是组合关系的就用组合,如果是工具类,就用第三种方法,都是看个人对问题的理解以及考虑以后的扩展去设计。有些人会说,如果这样的话,我何必还要通过传参数的方式把Animal传进来,一下这样也可以啊:

      

    package 疯狂java讲义;
    
    public class CommonTest2 {
    
        public static void main(String[] args) {
            Bird5 bird = new Bird5();
            Wolf4 wolf = new Wolf4();
            bird.Breath();
            bird.fly();
            wolf.Breath();
            wolf.run();
    
        }
    }
    
    class Animal5{
        private void beat(){
            System.out.println("心脏跳动");
        }
        public void breath(){
            beat();
            System.out.println("呼吸……");
        }
    }
    class Bird5{ 
        public void Breath(){
            Animal5 a = new Animal5();
            a.breath();
        }
        public void fly(){
            System.out.println("鸟会飞行……");
        }
    }
    
    class Wolf4{ 
        public void Breath(){
            Animal5 a = new Animal5();
            a.breath();
        }
        public void run(){
            System.out.println("狐狸会跑……");
        }
    }

      的确这样也是可以的如果Animal是一个通用类也可以说是工具类的时候,的确是可以这样的,并且这样和方式上一种方式也并没有什么区别,都不是属于继承和组合的方式,只是把Animal当做一个工具来使用,需要的时候就拿过来使用一下,完全是和面向对象无关的,和当前主业务是无关的,只是一个辅助品,就是一个手机,并非我们的必需品,你能拿手机跟我们的手相提并论么,手机要的时候我可以用一下,不需要的时候就丢掉,你自己的手你可以要就接上,不需要的时候就砍掉么?(当然,爱疯除外,很多人要爱疯不要肾……)就是因为手机是一个工具,对人来说只是一个附加品。如果手机只有一个或者要向别人借的,那就通过类外实例化传参数的方式(毕竟不能经常向别人借,这样总不好)。如果手机遍地都是,那就可以需要的时候才实例化一个手机出来用,自己慢慢理解了。既然说到了这里,那就再顺便说下,这就向是线程池或者数据库连接的连接池或者说是内存了,这些都是比较珍贵的资源或者说是对性能影响比较大的,这时候就最好是创建一个,然后能够重复利用,而每次需要的时候又重新创建一个的话,会导致开销很大,浪费很多资源。比如所Animal很大,new那么多对象出来就会很影响性能了。可能有人说,new 一个,在那个函数结束的时候,就已把Animal占用的资源释放了呀,哪有什么影响。其实虽然说作用域是结束了,但是对于像java或.net这些平台来说,作用域结束了,只是没有指针再指向堆里面的这个对象了,要等待GC回收才是真正释放了他所占的内存,所以,如果Animal很大的话,就会导致平台上的线程默认堆栈很快就到达了极限大小,然后触发GC回收,GC也是一个程序,也需要占用CPU,并且还会引起内存重组,防止出现内存碎片,所以如果是大对象或者是比较耗资源的对象就不要频繁地new一个出来,要有线程池和连接池的思想,new一个出来重复利用,这样能减少很多消耗,提高很多性能,所以告诫各位,千万别再一个循环里面new一个大对象,很容易导致宕机的,哈哈~~。但是如果像是string这些类,很小压根不占什么内存的,就可以在需要的时候就直接new一个出来就可以了。(注意:类大不大,是看类的属性多不多,并非方法;重不重要是看类对应管理的计算机资源缺不缺)

      其实这些模式都不是定死的,都是根据具体问题具体分析,不断变化不断发展不断完善的。

  • 相关阅读:
    HDU 3709 数位dp
    Educational Codeforces Round 64 (Rated for Div. 2)-C. Match Points
    POJ 1845乘法逆元+约数和
    POJ3696 欧拉定理
    NC24953 树形dp(最小支配集)
    Codeforces 1173 C 思维+模拟
    Codeforces 1324F 树形dp+换根
    codeforces-1285D(字典树)
    面向纯小白的CLion(C++)基于Windows的安装配置教程
    HDU-2825Wireless Password(AC自动机+状压DP)
  • 原文地址:https://www.cnblogs.com/ismallboy/p/5378379.html
Copyright © 2011-2022 走看看