Java继承与组合

参考资料

[1]. 疯狂Java讲义(第三版) 李刚

继承与组合

继承是实现类复用的重要手段,但继承带来了一个最大的坏处,破坏封装。相比之下,组合也是实现类复用的重要方式,而采用组合方式来实现类复用则能提供更好的封装性。

使用继承的注意点

为了保证父类有良好的封装性,不会被子类随意改变,设计父类通常应该遵循如下规则:
1. 尽量隐藏父类的内部数据。例如成员变量使用private修饰。
2. 不要让子类可以随意访问、修改父类的方法。例如父类中作为辅助和工具的方法设置为private;需要被外部类调用,又不希望被修改的方法,使用final修饰符;希望被重写,又不希望被其他类访问,则可以使用protected修饰符。
3. 尽量不要在父类中调用将要被子类重写的方法。
如果在子类中重写了父类在构造器中调用的方法,那么在实例化的时候父类会调用子类的重写的扩展方法。代码如下:

/**
 * 父类
 */
public class Base {
    /**
     * 构造器
     */
    public Base()
    {
        test();
    }

    public void test()           // ①号test()方法
    {
        System.out.println("将被子类重写的方法");
    }
}

子类


/**
 * 子类
 */
public class Sub extends Base{
    private String name;

    /**
     * 因为继承了父类
     * 所以父类在构造器中会调用此方法
     */
    public void test()         // ②号test()方法
    {
        System.out.println("子类重写父类的方法,"
                + "其name字符串长度" + name.length());
    }
    public static void main(String[] args)
    {
        // 下面代码会引发空指针异常
        // 直接父类会调用被子类重写的test方法
        Sub s = new Sub();
    }
}

类图如下:
这里写图片描述

利用组合实现复用

如果需要复用一个类,除了把这个类当成基类来继承之外,还可以把该类当成另一个类的组合成分,从而允许新类直接复用该类public方法。不管是继承还是组合,都允许在新类(对于继承就是子类)中直接复用旧类的方法。
Animal、Wolf、Bird三个类的代码如下:

class Animal
{
    private void beat()
    {
        System.out.println("心脏跳动...");
    }
    public void breath()
    {
        beat();
        System.out.println("吸一口气,吐一口气,呼吸中...");
    }
}
// 继承Animal,直接复用父类的breath()方法
class Bird extends Animal
{
    public void fly()
    {
        System.out.println("我在天空自在的飞翔...");
    }
}
// 继承Animal,直接复用父类的breath()方法
class Wolf extends Animal
{
    public void run()
    {
        System.out.println("我在陆地上的快速奔跑...");
    }
}
public class InheritTest
{
    public static void main(String[] args)
    {
        Bird b = new Bird();
        b.breath();
        b.fly();
        Wolf w = new Wolf();
        w.breath();
        w.run();
    }
}

类图如下:
这里写图片描述

现在使用组合的方式重写上面的类。



/**
 * Description:
 * <br/>网站: <a href="http://www.crazyit.org">疯狂Java联盟</a>
 * <br/>Copyright (C), 2001-2016, Yeeku.H.Lee
 * <br/>This program is protected by copyright laws.
 * <br/>Program Name:
 * <br/>Date:
 * @author Yeeku.H.Lee kongyeeku@163.com
 * @version 1.0
 */
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()
    {
        // 直接复用Animal提供的breath()方法来实现Bird的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()
    {
        // 直接复用Animal提供的breath()方法来实现Wolf的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();
    }
}

类图如下所示:
这里写图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值