zoukankan      html  css  js  c++  java
  • 第7章 在对象之间搬移特性

    简介

        在对象设计的过程中,“决定把责任放哪儿”是最重要的事情之一,如果没有放对地方,则采取重构。

        一个类常常可以通过“搬移字段”和“搬移函数”来简单移动对象达到重构目的;

        如果一个类还是臃肿不堪,则可以使用“提炼函数”的方法将一部分职责分出去;

        如果一个类变得太不负责任则可以使用“将类内联化”方法来重构;

        如果一个类使用了另一个类,且运用“隐藏委托关系”方法是有帮助的,则用此方法重构;

        如果当委托(中间人)变得没有必要,则可以使用“删除中间人”方法;

        最后“引入外加函数”和“引入本地扩展”是只有当不能访问某个类的源码,却又想把责任移进这个不修改的类时使用的两个重构方法,引进一个两个函数用前者,大于两个用后者。

    Move Method(搬移函数)

    1.概念:

    一个函数与另外一个A类中方法的交流多于与自己B类的交流,那么在A类中建立一个有着类似行为的新函数,将旧函数变成一个单纯的委托函数,或者将旧函数完全移除。

    2.动机:

    “搬移函数”是重构理论的支柱。如果类有太多行为或者两个类之间合作形成了高度耦合,则考虑用搬移函数。

    3.做法:

    觉得适合就搬,搬的时候考虑下迁移范围。

    Move Field(搬移字段)

    1.概念:

    在程序中的某个字段被自身类的其他类更多地用到,那么在目标类新建字段,并将之前旧字段换为新的字段。

    2.动机:

    一个类中的字段被另一个类更频繁地使用到了,这里的“使用”,可能是通过设置或者取值函数间接进行的。

    3.做法:

    顾名思义,想好就用。

    Extract Class(提炼类)

    1.概念:

    某个类做了两个类应该做的事,则建立一个新类,将相关字段和函数从旧类搬移到新类。

    2.动机:
    一个类应该是一个清楚的抽象,处理一些明确的责任。当一个类不断扩展,从而变得过分复杂,就要考虑梳理,提炼和迁移。

    3.做法:

    (1)分解一个类中所担负的责任。

    (2)建立新类,迁移,测试,从较低层函数开始。

    (3)删除旧类相应逻辑,精简每个类的接口。

    (4)决定是否公开新类。

    4.例子:

    之前我在实践中,一个类扩展得越来越复杂,于是会把事务和有业务逻辑相关的代码写在一起,后来同事给我提了很好的建议,就是将事务提出来单独放在一起,现在想到就是符合了“提炼类”的做法。

    Inline Class(将类内联化)

    1.概念:

    某个类没有做太多事情,就可以将这个类的所有特性搬移到另一个类中,然后移除原类。

    2.动机:

    通常因为此前重构动作移走了这个类的责任,后因需求改动发现这个类不再承担足够责任,因此可以再用“将类内联化”重构手法,将类合并。

    3.做法:

    合了测,测了删。

    Hide Delegate(隐藏委托关系)

    1.简介:客户通过一个委托类来调用另一个对象,则在服务类上建立客户所需的所有函数,用以隐藏委托关系。

    2.回顾:在第3章读书笔记《第三章 代码的坏味道》中的第15个坏味道里,过度耦合的消息链中提到了隐藏委关系,这里就不(lan)再(de)赘(xie)述(le)。

    Remove Middle Man(移除中间人)

    1.中间人概念:《第三章 代码的坏味道》的第16个坏味道里,介绍了中间人。

    2.做法:

    (1)建立一个函数,用以获得受托对象。

    (2)对于每个委托函数,在服务类中删除该函数,并让需要调用的客户转为调用受托对象。

    (3)处理每个委托函数后,编译,测试。

    Introduce Foreign Method(引入外加函数)

    1.概念:

    你需要为提供服务的类增加一个函数,但你无法修改这个类。于是你可以在客户端类中建立一个函数,并以第一参数形式传入一个服务类实例。

    2.动机:

    你正在使用一个类,它真的很好,为你的需求提供了所有服务,而后,新的需求要求你提供一项新的服务,这个类无法供应,如果这时还不能对这个类进行修改,则就只得在客户端编码,补足你要的函数。但如果发现需要在服务类建立大量的外加函数,则就不能再用“引入外加函数”方法重构,而是使用“引入本地扩展重构”。

    Introduce Local Extension(引入本地扩展)

    1.概念:

    你需要为服务类提供一些额外函数,但你无法修改这个类,则建立一个新类,使它包含这些额外函数,让这个扩展品成为源类的子类或包装类。

    2.动机:

        当你在服务端需要添加的外部函数超过了两个,则外加函数就很难控制它们了,所以你需要将这些函数组织在一起,放到一个恰当的地方去。要达到这一目的,两种标准对象技术--子类化和包装,统称为本地扩展。

        使用本地扩展使你得以坚持“函数和数据应该被统一封装”的原则。

    3.做法:

    (1)建立一个扩展类,将它作为原始类的子类或包装类。

    //用子类的方式(包装类使用暂略)
    class
    MfDateSub extends Date

    (2)在扩展类中加入转型构造函数(接受原对象作为参数的构造函数)。

    //加入转型构造函数
    public MfDateSub(Date arg) {
        super(arg.getTime());
    }
    
    //处理Date和扩展类之间的不同
    public MfDate(String dateString) {
        super(dateString);
    }

    (3)在扩展类中加入新特性。

    //搬移前
    client class...
        private static Date nextDay(Date arg) {
            //foreign method, should be on date
            return new Date (arg.getYear(), arg.getMonth(), arg.getDate() + 1);
        }
    //搬移后
    class MfDateSub...
        Date nextDay() {
            return new Date (getYear(), getMonth(), getDate() + 1);
        }

    (4)根据需要,将原对象替换为扩展对象。

    (5)将针对原始类定义的所有外加函数搬移到扩展类中。

  • 相关阅读:
    塔防游戏 代码project as 分享
    iOS网络监控— BMReachability
    Oracle学习(五):多表查询
    Servlet之生命周期【入门版(刚開始学习的人必看)】
    mysql 流程函数 存储引擎 InnoDB简单特性
    js
    UVa 10245
    Ubuntu14.04怎样使用root登录
    leetCode(29):Happy Number
    WebService:asp.net类库中添加WebService引用出现问题解决方法
  • 原文地址:https://www.cnblogs.com/wencheng9012/p/13554825.html
Copyright © 2011-2022 走看看