组合和继承——面向对象编程思想

在 1994 年,由 Erich Gamma、Richard Helm、Ralph Johnson 和 John Vlissides 四人合著出版了一本名为 Design Patterns - Elements of Reusable Object-Oriented Software(中文译名:设计模式 - 可复用的面向对象软件元素) 的书,该书首次提到了软件开发中设计模式的概念。

四位作者合称 GOF(四人帮,全拼 Gang of Four)。他们所提出的设计模式主要是基于以下的面向对象设计原则:

  • 对接口编程而不是对实现编程

  • 优先使用对象组合而不是继承

此处提到了对象组合和继承,那我们来看一下组合和继承的关系

继承(is-a)和组合(has-a)

Example:

要实现的目标:鸟(Bird)和狼(Wolf)都是动物(Animal),动物都有心跳(beat()),会呼吸(beat()),但是鸟会fly(fly()),狼会奔跑(run())

继承方式:

package inherit;
​
//inherit.InheritTest.java 使用继承方式实现目标
class Animal{
    private void beat(){
        System.out.println("心脏跳动...");
    }
​
    public void breath(){
        beat();
        System.out.println("吸一口气,呼一口气,呼吸中...");
    }
}
​
//继承Animal,直接复用父类的breath()方法
class Bird extends Animal{
    //创建子类独有的方法fly()
    public void fly(){
        System.out.println("我是鸟,我在天空中自由的飞翔...");
    }
}
​
//继承Animal,直接复用父类的breath()方法
class Wolf extends Animal{
    //创建子类独有的方法run()
    public void run(){
        System.out.println("我是狼,我在草原上快速奔跑...");
    }
}
​
public class InheritTest {
    public static void main(String[] args) {
        //创建继承自Animal的Bird对象新实例b
        Bird b=new Bird();
        //新对象实例b可以breath()
        b.breath();
        //新对象实例b可以fly()
        b.fly();
        Wolf w=new Wolf();
        w.breath();
        w.run();
/*
---------- 运行Java程序 ----------
心脏跳动...
吸一口气,呼一口气,呼吸中...
我是鸟,我在天空中自由的飞翔...
心脏跳动...
吸一口气,呼一口气,呼吸中...
我是狼,我在草原上快速奔跑...
​
输出完毕 (耗时 0 秒) - 正常终止
*/
    }
}

组合方式:

package composite;
​
//composite.CompositeTest.java  使用组合方式实现目标
class Animal{
    private void beat(){
        System.out.println("心脏跳动...");
    }
​
    public void breath(){
        beat();
        System.out.println("吸一口气,呼一口气,呼吸中...");
    }
}
​
class Bird{
    //定义一个Animal成员变量,以供组合之用
    private Animal a;
    //使用构造函数初始化成员变量
    public Bird(Animal a){
        this.a=a;
    }
    //通过调用成员变量的固有方法(a.breath())使新类具有相同的功能(breath())
    public void breath(){
        a.breath();
    }
    //为新类增加新的方法
    public void fly(){
        System.out.println("我是鸟,我在天空中自由的飞翔...");
    }
}
​
class Wolf{
    private Animal a;
    public Wolf(Animal a){
        this.a=a;
    }
    public void breath(){
        a.breath();
    }
    public void run(){
        System.out.println("我是狼,我在草原上快速奔跑...");
    }
}
​
public class CompositeTest{
    public static void main(String[] args) {
        //显式创建被组合的对象实例a1
        Animal a1=new Animal();
        //以a1为基础组合出新对象实例b
        Bird b=new Bird(a1);
        //新对象实例b可以breath()
        b.breath();
        //新对象实例b可以fly()
        b.fly();
        Animal a2=new Animal();
        Wolf w=new Wolf(a2);
        w.breath();
        w.run();
/*
---------- 运行Java程序 ----------
心脏跳动...
吸一口气,呼一口气,呼吸中...
我是鸟,我在天空中自由的飞翔...
心脏跳动...
吸一口气,呼一口气,呼吸中...
我是狼,我在草原上快速奔跑...
​
输出完毕 (耗时 0 秒) - 正常终止
*/
    }
}

总结

继承和组合都可以实现代码的复用

  • "is-a"(是)关系使用继承!

  • "has-a"(拥有)关系使用组合!

总结:
1)组合(has-a)关系可以显式地获得被包含类(继承中称为父类)的对象,而继承(is-a)则是隐式地获得父类的对象,被包含类和父类对应,而组合外部类和子类对应。
2)组合关系在运行期决定,而继承关系在编译期就已经决定了。
3)组合是在组合类和被包含类之间的一种松耦合关系,而继承则是父类和子类之间的一种紧耦合关系。
4)当选择使用组合关系时,在组合类中包含了外部类的对象,组合类可以调用外部类必须的方法,而使用继承关系时,父类的所有方法和变量都被子类无条件继承,子类不能选择。
5)最重要的一点,使用继承关系时,可以实现类型的回溯,即用父类变量引用子类对象,这样便可以实现多态,而组合没有这个特性。
6)还有一点需要注意,如果你确定复用另外一个类的方法永远不需要改变时,应该使用组合,因为组合只是简单地复用被包含类的接口,而继承除了复用父类的接口外,它甚至还可以覆盖这些接口,修改父类接口的默认实现,这个特性是组合所不具有的。
7)从逻辑上看,组合最主要地体现的是一种整体和部分的思想,例如在电脑类是由内存类,CPU类,硬盘类等等组成的,而继承则体现的是一种可以回溯的父子关系,子类也是父类的一个对象。
8)这两者的区别主要体现在类的抽象阶段,在分析类之间的关系时就应该确定是采用组合还是采用继承。
9)引用网友的一句很经典的话应该更能让大家分清继承和组合的区别:组合可以被说成“我请了个老头在我家里干活” ,继承则是“我父亲在家里帮我干活"。
  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
目 录 序言 前言 读者指南 第1章 引言 1 1.1 什么是设计模式 2 1.2 Smalltalk MVC中的设计模式 3 1.3 描述设计模式 4 1.4 设计模式的编目 5 1.5 组织编目 7 1.6 设计模式怎样解决设计问题 8 1.6.1 寻找合适的对象 8 1.6.2 决定对象的粒度 9 1.6.3 指定对象接口 9 1.6.4 描述对象的实现 10 1.6.5 运用复用机制 13 1.6.6 关联运行时刻和编译时刻的 结构 15 1.6.7 设计应支持变化 16 1.7 怎样选择设计模式 19 1.8 怎样使用设计模式 20 第2章 实例研究:设计一个文档编 辑器 22 2.1 设计问题 23 2.2 文档结构 23 2.2.1 递归组合 24 2.2.2 图元 25 2.2.3 组合模式 27 2.3 格式化 27 2.3.1 封装格式化算法 27 2.3.2 Compositor和Composition 27 2.3.3 策略模式 29 2.4 修饰用户界面 29 2.4.1 透明围栏 29 2.4.2 Monoglyph 30 2.4.3 Decorator 模式 32 2.5 支持多种视感标准 32 2.5.1 对象创建的抽象 32 2.5.2 工厂类和产品类 33 2.5.3 Abstract Factory模式 35 2.6 支持多种窗口系统 35 2.6.1 我们是否可以使用Abstract Factory 模式 35 2.6.2 封装实现依赖关系 35 2.6.3 Window和WindowImp 37 2.6.4 Bridge 模式 40 2.7 用户操作 40 2.7.1 封装一个请求 41 2.7.2 Command 类及其子类 41 2.7.3 撤消和重做 42 2.7.4 命令历史记录 42 2.7.5 Command 模式 44 2.8 拼写检查和断字处理 44 2.8.1 访问分散的信息 44 2.8.2 封装访问和遍历 45 2.8.3 Iterator类及其子类 46 2.8.4 Iterator模式 48 2.8.5 遍历和遍历过程中的动作 48 2.8.6 封装分析 48 2.8.7 Visitor 类及其子类 51 2.8.8 Visitor 模式 52 2.9 小结 53 第3章 创建型模式 54 3.1 Abstract Factory(抽象工厂)— 对象创建型模式 57 3.2 Builder(生成器)—对象创建型 模式 63 3.3 Factory Method(工厂方法)— 对象创建型模式 70 3.4 Prototype(原型)—对象创建型 模式 87 3.5 Singleton(单件)—对象创建型 模式 84 3.6 创建型模式的讨论 89 第4章 结构型模式 91 4.1 Adapter(适配器)—类对象结构型 模式 92 4.2 Bridge(桥接)—对象结构型 模式 100 4.3 Composite(组成)—对象结构型 模式 107 4.4 Decorator(装饰)—对象结构型 模式 115 4.5 FACADE(外观)—对象结构型 模式 121 4.6 Flyweight(享元)—对象结构型 模式 128 4.7 Proxy(代理)—对象结构型 模式 137 4.8 结构型模式的讨论 144 4.8.1 Adapter与Bridge 144 4.8.2 Composite、Decorator与Proxy 145 第5章 行为模式 147 5.1 CHAIN OF RESPONSIBIL ITY(职责链) —对象行为型模式 147 5.2 COMMAND(命令)—对象行为型 模式 154 5.3 INTERPRETER(解释器)—类行为型 模式 162 5.4 ITERATOR(迭代器)—对象行为型 模式 171 5.5 MEDIATOR(中介者)—对象行为型 模式 181 5.6 MEMENTO(备忘录)—对象行为型 模式 188 5.7 OBSERVER(观察者)—对象行为型 模式 194 5.8 STATE(状态)—对象行为型模式 201 5.9 STRATEGY(策略)—对象行为型 模式 208 5.10 TEMPLATE METHOD(模板方法) —类行为型模式 214 5.11 VISIT
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值