知识大全 代码复用的规则

Posted

篇首语:笛里谁知壮士心,沙头空照征人骨。本文由小常识网(cha138.com)小编为大家整理,主要介绍了知识大全 代码复用的规则相关的知识,希望对你有一定的参考价值。

  代码复用是绝大多数程序员所期望的 也是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) 那就说明你的代码是难以维护的 必须得到提高   一屏原则   如果一个函数的代码长度超过一个屏幕 那么或许这个函数太长了 应该拆分成更小的子函数   一行代码尽量简短 并且保证一行代码只做一件事    那种看似技巧性的冗长代码只会增加代码维护的难度      消除case / if语句   要尽量避免在代码中出现判断语句 来测试一个对象是否某个特定类的实例 通常 如果你需要这么做 那么 重新设计可能会有所帮助 我在工作中遇到这样的一个问题 我们在使用JAVA做XML解析时 对每个标签映射了一个JAVA类 采用SAX(简单的XML接口API Simple API for XML)模型 结果 代码中反复出现了大量的判断语句 来测试当前的标签类型 为此 我们重新设计了DTD(文档类型定义 Document Type Definition) 为每个标签增加了一个固定的属性 classname 而且重新设计了每个标签映射的JAVA类的接口 统一了每个对象的操作 addElement(Element aElement); //增加子元素  addAttribute(String attName String attValue); //增加属性     则彻底消除了所有的测试当前的标签类型的判断语句 每个对象通过 Class forName(aElement attributes getAttribute( classname )) newInstence(); 动态创建      减少参数个数   有大量参数需要传递的方法 通常很难阅读 我们可以将所有参数封装到一个对象中来完成对象的传递 这也有利于错误跟踪     许多程序员因为 太多层的对象包装对系统效率有影响 是的 但是 和它带来的好处相比 我们宁愿做包装 毕竟 封装 也是OO的基本特性之一 而且 每个对象完成尽量少(而且简单)的功能 也是OO的一个基本原则      类层次的最高层应该是抽象类   在许多情况下 提供一个抽象基类有利做特性化扩展 由于在抽象基类中 大部分的功能和行为已经定义好 使我们更容易理解接口设计者的意图是什么     由于JAVA不允许 多继承 从一个抽象基类继承 就无法再从其它基类继承了 所以 提供一个抽象接口(interface)是个好主意 一个类可以实现多个接口 从而模拟实现了 多继承 为类的设计提供了更大的灵活性      尽量减少对变量的直接访问   对数据的封装原则应该规范化 不要把一个类的属性暴露给其它类 而是应该通过访问方法去保护他们 这有利于避免产生波纹效应 如果某个属性的名字改变 你只需要修改它的访问方法 而不是修改所有相关的代码      子类应该特性化 完成特殊功能   如果一个子类只是使一个组件变成组件管理器 而不是实现接口功能 或者 重载某个功能 那么 就应该使用一个外部的容器类 而不是创建一个子类     建议 类层次结构图 不要太深     例如 下面的接口定义了组件的功能 发送消息 类Transceiver实现了该接口 而其子类Pool只是管理多个Transceiver对象 而没有提供自己的接口实现 建议使用组合方式 而不是继承!  public interface ITransceiver   public abstract send(String msg);      public class Transceiver implements ITransceiver    public send(String msg)   System out println(msg);         //使用继承方式的实现  public class Pool extends Transceiver   private List pool = new Vector();   public void add(Transceiver aTransceiver)   pool add(aTransceiver);    public Transceiver get(int index)   pool get(index);        //使用组合方式的实现  public class Pool    private List pool = new Vector(); cha138/Article/program/Java/hx/201311/26568

相关参考

知识大全 .NET2005提供的Code Snippets看代码复用

.NET2005提供的CodeSnippets看代码复用  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下

知识大全 Java中可复用事件处理的设计与实现代码

Java中可复用事件处理的设计与实现代码  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  目前面向

普通发票代码有何规定的?

普通发票代码的内容、编制规则及启用时间是如何规定的  为便于全国普通发票统一识别和查询,自2004年7月1日起,在全国统一启用12位分类代码和8位发票号码的普通发票。普通发票代码由国地税代码、行政区域

深井煤矿涌水直接净化与复用技术的研究

国内煤矿年排矿井水很大,但利用率不到20%,造成水资源浪费。三河尖煤矿根据自身的特点,研发了井下一体化自动净化与复用水系统,其中2200t/d净化水在井下直接复用防尘,剩余约1000t清洁水上排到地面

深井煤矿涌水直接净化与复用技术的研究

国内煤矿年排矿井水很大,但利用率不到20%,造成水资源浪费。三河尖煤矿根据自身的特点,研发了井下一体化自动净化与复用水系统,其中2200t/d净化水在井下直接复用防尘,剩余约1000t清洁水上排到地面

深井煤矿涌水直接净化与复用技术的研究

国内煤矿年排矿井水很大,但利用率不到20%,造成水资源浪费。三河尖煤矿根据自身的特点,研发了井下一体化自动净化与复用水系统,其中2200t/d净化水在井下直接复用防尘,剩余约1000t清洁水上排到地面

透析器复用有哪些优缺点?

(1)复用的优点:①降低透析费用;②减少透析中症状的发生率,如首次使用综合征;③提高透析器的生物相容性。  (2)缺点:①透析器的效率减低,因透析器内残留血量减少有效透析面积所致;②发生感染机会增加;

透析器复用有哪些优缺点?

(1)复用的优点:①降低透析费用;②减少透析中症状的发生率,如首次使用综合征;③提高透析器的生物相容性。  (2)缺点:①透析器的效率减低,因透析器内残留血量减少有效透析面积所致;②发生感染机会增加;

知识大全 Java程序性能优化-对象复用“池”(5)

Java程序性能优化-对象复用“池”(5)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb

知识大全 Java程序性能优化-对象复用“池”(1)

Java程序性能优化-对象复用“池”(1)  以下文字资料是由(全榜网网www.cha138.com)小编为大家搜集整理后发布的内容,让我们赶快一起来看一下吧!  &nb