`
IT-future
  • 浏览: 29807 次
  • 来自: ...
最近访客 更多访客>>
文章分类
社区版块
存档分类
最新评论

代码复用的规则(上)

阅读更多

    代码复用是绝大多数程序员所期望的,也是OO的目标之一。总结我多年的编码经验,为了使代码能够最大程度上复用,应该特别注意以下几个方面。

  对接口编程

  "对接口编程"是面向对象设计(OOD)的第一个基本原则。它的含义是:使用接口和同类型的组件通讯,即,对于所有完成相同功能的组件,应该抽象出一个接口,它们都实现该接口。具体到JAVA中,可以是接口(interface),或者是抽象类(abstract class),所有完成相同功能的组件都实现该接口,或者从该抽象类继承。我们的客户代码只应该和该接口通讯,这样,当我们需要用其它组件完成任务时,只需要替换该接口的实现,而我们代码的其它部分不需要改变!
  当现有的组件不能满足要求时,我们可以创建新的组件,实现该接口,或者,直接对现有的组件进行扩展,由子类去完成扩展的功能。

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

  "优先使用对象组合,而不是类继承"是面向对象设计的第二个原则。并不是说继承不重要,而是因为每个学习OOP的人都知道OO的基本特性之一就是继承,以至于继承已经被滥用了,而对象组合技术往往被忽视了。下面分析继承和组合的优缺点:

  类继承允许你根据其他类的实现来定义一个类的实现。这种通过生成子类的复用通常被称为白箱复用(white-box reuse)。术语"白箱"是相对可视性而言:在继承方式中,父类的内部细节对子类可见。

  对象组合是类继承之外的另一种复用选择。新的更复杂的功能可以通过组合对象来获得。对象组合要求对象具有良好定义的接口。这种复用风格被称为黑箱复用(black-box reuse),因为被组合的对象的内部细节是不可见的。对象只以"黑箱"的形式出现。

  继承和组合各有优缺点。类继承是在编译时刻静态定义的,且可直接使用,类继承可以较方便地改变父类的实现。但是类继承也有一些不足之处。首先,因为继承在编译时刻就定义了,所以无法在运行时刻改变从父类继承的实现。更糟的是,父类通常至少定义了子类的部分行为,父类的任何改变都可能影响子类的行为。如果继承下来的实现不适合解决新的问题,则父类必须重写或被其他更适合的类替换。这种依赖关系限制了灵活性并最终限制了复用性。

  对象组合是通过获得对其他对象的引用而在运行时刻动态定义的。由于组合要求对象具有良好定义的接口,而且,对象只能通过接口访问,所以我们并不破坏封装性;只要类型一致,运行时刻还可以用一个对象来替代另一个对象;更进一步,因为对象的实现是基于接口写的,所以实现上存在较少的依赖关系。

  优先使用对象组合有助于你保持每个类被封装,并且只集中完成单个任务。这样类和类继承层次会保持较小规模,并且不太可能增长为不可控制的庞然大物(这正是滥用继承的后果)。另一方面,基于对象组合的设计会有更多的对象(但只有较少的类),且系统的行为将依赖于对象间的关系而不是被定义在某个类中。

  注意:理想情况下,我们不用为获得复用而去创建新的组件,只需要使用对象组合技术,通过组装已有的组件就能获得需要的功能。但是事实很少如此,因为可用的组件集合并不丰富。使用继承的复用使得创建新的组件要比组装已有的组件来得容易。这样,继承和对象组合常一起使用。然而,正如前面所说,千万不要滥用继承而忽视了对象组合技术。

  相关的设计模式有: Bridge、Composite、Decorator、Observer、Strategy等。

  下面的例子演示了这个规则,它的前提是:我们对同一个数据结构,需要以任意的格式输出。

  第一个例子,我们使用基于继承的框架,可以看到,它很难维护和扩展。

abstract class AbstractExampleDocument
{
    // skip some code ...
    public void output(Example structure)
        {
            if( null != structure )
                {
                this.format( structure );
                }
        }
    protected void format(Example structure);
}

  第二个例子,我们使用基于对象组合技术的框架,每个对象的任务都清楚的分离开来,我们可以替换、扩展格式类,而不用考虑其它的任何事情。

class DefaultExampleDocument
{
  // skip some code ...
  public void output(Example structure)
  {
     ExampleFormatter formatter =
       (ExampleFormatter) manager.lookup(Roles.FORMATTER);
     if( null != structure )
     {
       formatter.format(structure);
     }
  }
}

  这里,用到了类似于"抽象工厂"的组件创建模式,它将组件的创建过程交给manager来完成;ExampleFormatter是所有格式的抽象父类;

  将可变的部分和不可变的部分分离

  "将可变的部分和不可变的部分分离"是面向对象设计的第三个原则。如果使用继承的复用技术,我们可以在抽象基类中定义好不可变的部分,而由其子类去具体实现可变的部分,不可变的部分不需要重复定义,而且便于维护。如果使用对象组合的复用技术,我们可以定义好不可变的部分,而可变的部分可以由不同的组件实现,根据需要,在运行时动态配置。这样,我们就有更多的时间关注可变的部分。

  对于对象组合技术而言,每个组件只完成相对较小的功能,相互之间耦合比较松散,复用率较高,通过组合,就能获得新的功能。

  减少方法的长度

  通常,我们的方法应该只有尽量少的几行,太长的方法会难以理解,而且,如果方法太长,则应该重新设计。对此,可以总结为以下原则:

  ☆ 三十秒原则:如果另一个程序员无法在三十秒之内了解你的函数做了什么(What),如何做(How)以及为什么要这样做(Why),那就说明你的代码是难以维护的,必须得到提高;
  ☆ 一屏原则:如果一个函数的代码长度超过一个屏幕,那么或许这个函数太长了,应该拆分成更小的子函数;
  ☆ 一行代码尽量简短,并且保证一行代码只做一件事:那种看似技巧性的冗长代码只会增加代码维护的难度。



分享到:
评论

相关推荐

    SOC平台 verilog 代码风格规范V0.4.doc

    4.2 命名规则 5 4.2.1 基本命名标准 5 4.2.2 命名准则 6 4.3 VERILOG HDL源代码文件结构 10 4.3.1 VERILOG HDL 代码文件文件头 10 4.3.2 VERILOG HDL 代码文件宏定义 13 4.3.3 VERILOG HDL 代码文件模块名及端口信号...

    毕业设计:ASP校友录设计(源代码)

    本设计中使用代码复用机制,即在开发中尽量使用本系统中已经使用过的代码,以及使用以前项目积累的代码,如分页功能、检查E-mail的函数。 3 使用数据库连接池和其他优化手段 连接数据库采用ODBC方式,并且在每页...

    dotnetcoding ORM 代码生成器

    DotNetCoding(http//www.dotnetcoding.net)是一款帮助...采用此开发平台,能够复用成熟的开发架构,自动生成所有非商业有关的代码,在公司范围内不断的积累开发技能和经验,极大的提高开发效率,规范开发,提高开发质量。

    编写高质量代码-Web前端开发修炼之道.azw3

    kindle高清文字版,可在电脑上用clearview电子书阅读软件阅读。 第1章 从网站重构说起 1.1 糟糕的页面实现,头疼的维护工作 1.2 Web标准——结构、样式和行为的分离 1.3 前端的现状 1.4 打造高品质的前端代码,...

    liteFlow规则引擎框架.rar

    代码的抽象,复用率也越来越低,各个模块之间的耦合度很高。一小段逻辑的变动,会影响到其他模块,需要进行完整回归测试来验证。如要灵活改变业务流程的顺序,则要进行代码大改动进行抽象,重新写方法。实时热变更...

    STL学习过程中的代码笔记

    通过使用模板,可以将代码的通用部分抽象出来,提高代码的复用性和可维护性。同时,STL中的各种容器和算法也都是通过模板实现的,这使得STL在处理不同类型的数据时表现出色。总的来说,学习STL是我编程之路中的一次...

    JAVA上百实例源码以及开源项目源代码

     Java二进制IO类与文件复制操作实例,好像是一本书的例子,源代码有的是独立运行的,与同目录下的其它代码文件互不联系,这些代码面向初级、中级Java程序员。 Java访问权限控制源代码 1个目标文件 摘要:Java源码,...

    可复用构件的框架表示与检索* (2008年)

    提出了基于人工智能框架知识表示的构件描述方法,以解决构件描述、分类、检索等构件复用关键性问题;并利用框架表示的推理特性,建立了基于规则推理和功能粒度的构件搜索匹配算法,提高构件搜索效率和准确性。

    COM技术内幕——微软组件对象模型--随书源代码

    7.1.3 类上下文 104 7.1.4 客户程序清单 105 7.1.5 CoCreateInstance的不灵活性 107 7.2 类厂 107 7.2.1 CoGetClassObject 107 7.2.2 IClassFactory 108 7.2.3 CoCreateInstance与CoGetClassObjet的比较 109 ...

    Android代码-Android平台中对页面、原生路由功能的中间件.

    (目前市面上路由组件都很难配套动态插件化方案) 接入和使用简单易懂; 扩展性极强,满足项目苛刻要求; 请求对象池复用; 代码简洁优美; Demo展示 Demo apk下载、Demo Gif 一、功能介绍 模块间调用 网页和原生之间...

    TvHorizontalFlowLayout:电视launcher的不规则布局会更新变动,不想在xml中写死,试试代码构建吧,只需几行代码,配置大小与方位

    1、每个page页的布局是不规则的且都不一样,导致无法复用。 2、有线上更新布局的需求或下拉加载(通过接口拿到图片,并且图片的大小可能会变动) 导致page的布局不能在xml中写死,但是通过代码一个个addView又很麻烦。...

    vue-multiple-tabs:vue-cli3 动态路由, 复用路由, 自动注入路由, 增删路由, 实战多tab页

    代码Eslint 规则修改,消除warning 使用 Placeholder... 预览 本地使用 # download git clone https://github.com/BiYuqi/vue-multiple-tabs-use-one-component.git # install dependencies npm install # serve ...

    基于可逆计算原理从零开始构建的新一代低代码平台,它致力于克服低代码平台无法摆脱穷举法的困境,从理论层面超越组件技术,有效的解决粗

    Nop Platform 2.0是基于可逆计算理论实现的低代码开发平台,它致力于克服低代码平台无法摆脱穷举法的困境,从理论层面超越组件技术,有效的解决粗粒度软件复用的问题;包含GraphQL引擎、ORM引擎、工作流引擎、报表...

    Python编程规范要求

    6. 模块和包的组织:将相关的功能封装在模块和包中,使代码结构清晰,并且可以方便地复用。 7. 代码风格:遵循PEP 8规范,包括使用空格而不是制表符进行缩进、每行代码不超过79个字符等。 遵循Python编程规范可以使...

    重构到设计模式的经典案例,超完美详细(java源码)

    * 这段代码根本不可能在输出xml的代码中复用report()的任何行为,唯一 * 可以做的就是重写一个xmlReport(),大量重复report()中的行为,当然, * 现在这个修改还不费劲,拷贝一份report()直接修改就是了。 * ...

    精通MFC (光盘) 源代码

    15.1.5 COMK 的功能复用 15.2 IUnknown接口在MFC中的实现 15.2.1 内部类 15.2.2 接口映射类 15.2.3 聚合的实现 15.3 类厂及其MFC实现 15.3.1 ColeObjectFactory类 15.3.2 全局类厂链 15.3.3 类厂的注册/反...

    vue框架介绍的一些简介

    组件化:Vue.js通过组件化的方式,将实现页面某一部分功能的结构、样式和逻辑封装成为一个整体,使其高内聚、低耦合,从而提高代码复用率,并使代码更易于维护。 声明式编码:Vue.js采用声明式编码,让编码人员无需...

    毕业设计-ssm构建彩虹猫购物商城.zip

    毕业设计-项目完整代码+sql. 简介地址:https://mp.csdn.net/postedit/102697257 购物商城 主要模块(前后端): 用户模块:横向越权、纵向越权、MD5明文加密、guava缓存高复用服务响应对象的设计思想和封装  ...

    吕鑫:最博大精深的C语言视频教程 第23天 【第3堂课】函数指针与回调函数的应用

    1、演示按照多种规则进行排序的代码优化,提高代码复用性的方法; 2、讲解函数指针的概念与使用方法; 3、演示回调函数在项目开发中的应用;

Global site tag (gtag.js) - Google Analytics