面向接口编程(A)
前面的章节对于本篇来说,只是基础和铺垫,而且讲的很简单,因为那些很容易理解。我们从这个章节开始,用大量的代码的配合,来阐述面向接口编程。

接口的演化形式
现在我们回顾一下继承相关的知识。我们现在给出一组新的继承体系。它们是和图形相关的,我们可以假设这样的一种需求,就是我们要实现一个画图板(例如Windows的画图板),至少要能在上面绘制几个圆形和矩形。于是,我们很自然底定义了如下的classes。

class Shape    //abstract in fact
{
    public virtual void draw();
}

class Circle : Shape
{
    public override void draw()
    {
        /* draw a circle on some device */
    }
}

class Rect : Shape
{
    public override void draw()
    {
        /* draw a Rect on some device */
    }
}

首先要说的是,我们确实是无法给出Shape类的方法draw()的实现。因为它是一个抽象的类型(不要和语言中的抽象类或abstract关键字混淆,但是它们确实有莫大的联系,但是我所谓的抽象是一种真实的抽象),我们不知道一个所谓的“图形”应该如何被画出来。这就像你让我画一个图形出来一样,我感到很为难。我画个圆圈或者是多边形,五角星,似乎都不是一个具有抽象意义的图形。

我们再回顾一下多态,下面的代码更好的诠释了多态的作用。

Array<Shape> shapes = { new Circle(), new Rect(), new Circle(), new Circle(), new Rect() };

void drawShapes()
{
    foreach(Shape shape in shapes)
    {
        shape.draw();
    }
}

这是一段伪码,但是很自然地表现除了多态的从容,foreach从容器中循环枚举出Shape类的各种不同的派生类对象,它们都多态性地调用了它们各自类型的draw()方法。而这个过程又绝没有很明显的显露出某一个具体的派生类的类型的参与。于是,我们还可以很自然地再派生出圆角矩形,或者是五角星,都让它们继承自Shape类即可,它们也可以很自然地被放进shapes容器中,而且又不会修改循环处的分毫代码,这就是我们所追求的可扩展性和“新增代码不会影响已有的代码”。

嗯,这一切都很完美,不是嘛? 然而,这真的很完美嘛?

表格(Table)是一个Shape(对象)嘛?文本(Text)是一个Shape嘛?如果我们要有若干个图层(Layer),每一个图层是一个Shape嘛?如果是,这些出现在画图板上的元素,它们很好的诠释了is-a的信念嘛?

没有,因为一个Table不是一个Shape,Text也不是Shape,但是它们也都可以被画在上面,于是我们需要进行一次重要的演化。

我们在C++的语法教材中不强调接口的概念,而是用纯抽象类来表达这一个含义,但是我更愿意用Java的interface关键字作为表达。但是我们要清楚,无论是接口,还是基类,抽象基类,多态性都是存在于这样的语法关系中的。

interface IDraw {
    void draw();
}

class Circle implements IDraw {
    void draw() {
        /* draw a circle on some device */
    }
}

class Rect implements IDraw {
    void draw() {
        /* draw a Rect on some device */
    }
}

这次演化,似乎是没有本质改变的,特别是对于C++的编译器来说,编译出来的代码都可能没有丝毫的不同。也许很多人开始叹气了,认为这种形式上的变化根本是无所谓的,甚至就是在浪费时间。
但是我想说的是,对于设计来说,这种变化是本质的变化。因为对象的关系变化了,之前,我们说一个Circle对象也是一个Shape,它满足is-a的经典关系,但是现在,这种关系被打破了。

Can-do & Constraint
我们在前面的章节中,已经提到了has-a和is-a的对象关系了,现在,我们的重点是can-do的关系,这种关系表示约束(Constraint)。
于是,在上面的代码中,我们说Circle类实现了IDraw接口,或者说Circle对象能够完成IDraw接口所要求的行为。

void draw(IDraw d)
{
    d.draw();
}

而这个函数就更直观地表达出约束的概念了,“画可画之对象”,准确地说,这个函数更直接地完成 IDraw接口的约束语义表达:只有实现了约束的对象才可以被传入,并调用其draw()方法(注意,而并不是有draw()方法的对象都可以被传入和调用,相关问题可以对比C++09的concept)。

Array<IDraw> drawList = { new Circle(), new Rect(), new Circle(), new Table(), new Rect(), new TextArea() };

void draw()
{
    foreach(IDraw d in drawList )
    {
        d.draw();
    }
}

我用这段伪码,明确地表示了这样的一个新情况,Circle被画到画图板中去了,Table和TextArea也可以被画到上面去了。

依然是存有怀疑,难道Table派生自Shape就有问题嘛?难道一定要弄出一个IDraw,让它看起来有道理才是合理的?
不是的。首先,如果IDraw接口没有取代Shape类,我们也要承认这样几个事情,Shape类还是带着IDraw接口的含义,尽管我们不把它抽象出来。

而且,设计没有对错之分,是不是适应需求才是最实际的评判标准。我们当前的例子还很简单,我们只涉及到了元素的绘制(draw),但是也许还有其他的问题 (新需求总是很多的),比如ALPHA混合,图层的遮挡,元素的选择,蚂蚁线的绘制,等等。例如,当我们选择了一个Rect的时候,他的四周有蚂蚁线,而我们选择了一个TextAread的时候,它的四周是带有8个调节点的边框。可是,我们不打算让蚂蚁线和边框参与其他元素的遮挡计算和ALPHA混合计算,而且它们也不参与序列化,于是,它们既不是Shape,也不应该实现IDraw接口。经验告诉我们,Shape类是不足以成为所有元素的基类的,IDraw接口也不是万能的。具体的解决方案要看需求,如何应对这些需求,我们会在后面的内容中有所涉及。


转载于:https://www.cnblogs.com/healerkx/articles/1233252.html

面向对象理论(6)-Interface Programming-[A]相关推荐

  1. Vision-based User Interface Programming in Java一书简介

    1.概述 <Vision-based User Interface Programming in Java>这本书介绍了如何用java做摄像头程序和游戏,可以作为一个计算机视觉的启蒙读物. ...

  2. Python编程基础:第三十九节 面向对象编程Object Oriented Programming

    第三十九节 面向对象编程Object Oriented Programming 前言 实践 前言 到目前为止我们都是函数式编程,也即将每一个功能块写为一个函数.其实还有一种更常用的编程方式被称为面向对 ...

  3. java 接口对象_Java面向对象之接口——interface

    Java面向对象之接口--interface 什么是接口 一般计算机中的接口分为硬件接口和软件接口. 硬件接口:是指两个硬件设备之间的连接方式,既包括物理上的接口,还包括逻辑上的数据传送协议. 软件接 ...

  4. 面向对象编程(Object-Oriented Programming)

    如果你看透了表面现象就会发现,其实"面向对象编程"本身没有引入很多新东西.所谓"面向对象语言",其实就是经典的"过程式语言"(比如Pasca ...

  5. java 设计模式:软件设计原则、面向对象理论、23 种设计模式

    文章目录 软件设计原则 1.单一职责原则(Single Responsibility Principle) 2.开闭原则(Open Closed Principle) 3.里氏代换原则(Liskov ...

  6. 面向对象编程 object oriented programming(OOP)

    面向对象编程,是一种编程方式,这种编程方式需要使用"对象"来实现 对象的特征 世间万物皆对象 每个对象都是唯一的 对象具有属性和行为(对象的行为包括具有的功能及具体的实现) 对象具 ...

  7. javaScript设计模式之面向对象编程(object-oriented programming,OOP)(二)

    接上一篇 面向对象编程的理解? 答:面向对象编程,就是将你的需求抽象成一个对象,然后针对这个对象分析其特征(属性)与动作(方法).这个对象我们称之为类.面向对象编程思想其中一个特点就是封装,就是把你需 ...

  8. python, 面向对象编程Object Oriented Programming(OOP)

    把对象作为程序的基本单元,一个对象包含了数据和操作数据的函数. 面向过程的程序设计把计算机程序视为一系列的命令集合,即一组函数的顺序执行.为了简化程序设计,面向过程把函数继续切分为子函数,即把大块函数 ...

  9. BioPython ② | 面向对象编程Object Oriented Programming

    BioPython ② | Python面向对象编程 题目要求 定义分子类(Molecule)作为基类,包含集合elements和weight作为其属性,用初始化函数,将elements初始化为空集, ...

最新文章

  1. Matlab与线性代数 -- 矩阵的右除
  2. WindowsAPI开发常用资料
  3. linux 查找目录或文件
  4. range 和 xrange
  5. SAP Spartacus Unit List Component的设计明细 - UnitListComponent
  6. Android11怎么截屏,对标IOS?Android11或无缘屏幕长截图
  7. 云数据库·ApsaraDB 产品6月刊
  8. avr计数_使用8位LCD创建计数器| AVR
  9. 实现路由器无线接收另一个路由器无线信号搭建网络
  10. C++笔记-QSslSocket::supportsSsl返回false(windows版的Qt不支持SSL)解决
  11. Spring Boot笔记-目前对Web后端开发的认识
  12. C#实现利用单选框实现更改文本的richTextBox字体、大小、加粗
  13. 疫情之下,精准测试的智能可信模式正在成为中流砥柱
  14. Oracle刷建表语句
  15. 计算机二级考试c语言 上机,计算机等级考试二级C语言上机题[2]
  16. Git版本控制及Goland使用Git教程
  17. 山东大学软件学院《数据仓库与数据挖掘》复习知识点
  18. select2.js插件支持拼音搜索(最新版-4.0.6)
  19. 桥本分数式(蓝桥杯)
  20. 服务器启动首选项不是虚拟盘,没法开启CPU虚拟化,BIOS没有开启的选项

热门文章

  1. pytorch默认初始化_“最全PyTorch分布式教程”来了!
  2. Spring AOP通知顺序
  3. 制表符补全位数在idea和eclipse中的区别
  4. JavaWeb-JavaMail邮件开发
  5. linux更改用户的shell,Linux下通过shell更改用户密码
  6. 360浏览器极速模式_【小技巧】解除浏览器主页以及,锁定主页~
  7. console 立即输出 调试_Javascript调试利器console的使用
  8. java语言只保留了什么_java语言的保留的关键字【小白必读】
  9. 排序 np_P问题、NP问题、NP完全问题和NP难问题理解
  10. stm32如何执行软复位_stm32 上电复位 跟软复位有什么区别