zoukankan      html  css  js  c++  java
  • 重构改善既有代码的设计--简化函数调用

    前言:关于缩减参数列的重构手法,Doug Lea对我提出了一个警告:并发编程往往需要使用较长的参数列,因为这样你可以保证传递给函数的参数都是不可被修改的,例如内置型对象和值对象一定是不可变的。通常,你可以使用不可变对象取代这样的长参数列,但另一方面你也必须对此类重构保持谨慎。

    多年来,我一直坚守一个很有价值的习惯:明确地将“修改对象状态”的函数(修改函数)和“查询对象状态”的函数(查询函数)分开设计。

    1、Rename Method(函数改名)

    动机:函数的名称未能揭示函数的用途。

    2、Add Parameter(添加参数)

    动机:某个函数需要从调用端得到更多信息。

    3、Remove Parameter(移除参数)

    动机:函数本体不再需要某个参数

    4、Separate Query from Modifier(将查询函数和修改函数分离)

    动机:某个函数既返回对象状态值,有修改对象状态。

    做法:建立两个不同的函数,其中一个负责查询,另一个负责修改。

    5、Parameterize Method(令函数携带参数)

    动机:若干函数做了类似的工作,但在函数本体中却包含了不同的值。

    做法:建立单一函数,以参数表达那些不同的值。

    代码1

    void tenPercentRaise(){

    salary *= 1.1;

    }

    void fivePercentRaise(){

    salary *= 1.05;

    }

    代码2:上述代码可以替换如下

    void raise(double factor){

    salary *= (1 + factor);

    }

    6、Replace Parameter with Explicit Methods(以明确函数取代参数)

    代码1

    static final int ENGINEER = 0;

    static final int SALESMAN = 1;

    static final int MANAGER = 2;

    static Employee create(int type){

    switch(type){

    case ENGINEER:

    return new Engineer();

    }

    case ENGINEER:

    return new Salesman();

    }

    case ENGINEER:

    return new Manager();

    }

    default :

    throw new IllegalArgumentException("Incorrect type code value");

    }

    代码2

    static Employee createEngineer(){

    return new Engineer();

    }

    static Employee createSalesman(){

    return new Salesman();

    }

    static Employee createManager(){

    return new Manager();

    }

    7、Preserve Whole Object(保持对象完整)

    动机:你从某个对象中取出若干值,将它们作为某一次函数调用时的参数。

    做法:改为传递整个对象。

    代码1int low = daysTempRange().getLow();

    int high = daysTempRange().getHigh();

    withinPlan = plan.withinRange(low, high);

    代码2withinPlan = plan.withinRange(daysTempRange());

    8、Replace Parameter With Methods(以函数取代参数)

    动机:对象调用某个函数,并将所得结果作为参数,传递给另一个函数。而接受该参数的函数本身也能够调用前一个函数。

    做法:让参数接受者去除该项参数,并直接调用前一个函数。

    代码1

    int basePrice = _quantity * _itemPrice;

    discountLevel = getDiscountLevel();

    double finalPrice = discountedPrice(basePricediscountLevel);

    代码2

    int basePrice = _quantity * _itemPrice;

    double finalPrice = discountedPrice(basePrice);

    9、Introduce Parameter Object(引入参数对象)

    某些参数总是很自然地同时出现,这时可以以一个对象取代这些参数。价值在于缩短参数列。

    做法:新建一个类,用以表现你想替换的一组参数。将这个类设为不可变的。

    比如:

    private final Date _start;

    private final Date _end;

    DateRange(Date start, Date end){

    _start = start;

    _end = end;

    }

    Date getStart(){

    return _start;

    }

    Date getEnd(){

    return _end;

    }

    10、Remove Setting Method(移除设值函数)

    动机:类中的某个字段应该在对象创建时被设值,然后就不可再改变。

    做法:去掉该字段的所有设值函数。

    11、Hide Method(隐藏函数)

    动机:有一个函数,从来没有被其他任何类用到。应该将这个函数修改为private

    12、Replace Constructor with Factory Method(以工厂函数取代构造函数)

    动机:你希望在创建对象时不仅仅是做简单的构建动作。

    范式1:根据整数(实际是类型码)创建对象

    class Employee{

    private int _type;

    static final int ENGINEER = 0;

    static final int SALESMAN = 1;

    static final int MANAGER = 2;

    Employee(int type){

    _type = type;

    }

    static create(int type){

    return new Employee(type);

    }

    static Employee create(int type){

    switch(type){

    case ENGINEER:

    return new Engineer();

    case SALESMAN:

    return new Salesman();

    case MANAGER:

    return new Manager();

    default:

    throw new IllegalArgumentException("Incorrect type code value");

    }

    }

    }

    调用:Employee eng = Employee.create(Employee.ENGINEER);

    范式2:根据字符串创建子类对象

    static Employee create(String name){

    try{

    return (Employee)Class.forName(name).newInstance();

    }catch(Exception e){

    throw new IllegalArgumentException("Unable to instantiate" + name);

    }

    }

    调用:Employee.create(“Engineer”);

    范式3:以明确函数创建子类

    class Person...

    static Person createMale(){

    return new Male();

    }

    static Person createFemale(){

    return new Female();

    }

    调用:Person kent = Person.createMale();

    13、Encapsulate Downcase(封装向下转型)

    动机:某个函数返回的对象,需要调用者执行向下转型

    做法:将向下转型动作转移到函数中。

    Object lastReading(){

    return readings.lastElement();

    }

    Reading lastReading(){

    return (Reading)readings.lastElement();

    }

    14、Replace Error Code with Exception(以异常取代错误码)

    动机:某个函数返回一个特定的代码,用以表示某种错误情况。

    代码1int withdraw(int amount){

    if(amount > _balance){

    return -1;

    }

    else{

    _balance -= amount;

    return 0;

    }

    }

    代码2void withdraw(int amount)throws BalanceException{

    if(amount > _balance)throw new BalanceException();

    _balance -= amount;

    }

    15、Replace Exception with Test(以测试取代异常)

    代码1

    double getValueForPeriod(int periodNumber){

    try{

    return _values[periodNumber];

    }catch(ArrayIndexOutofBoundsException e){

    return 0;

    }

    }

    代码2

    double getValueForPeriod(int periodNumber){

    if(periodNumber >= _values.length) return 0;

    return _values[periodNumber];

    }

    代码3

    Resource getResource(){

    try{

    result = (Resource) _available.pop();

    _allocated.push(result);

    return result;

    }catch(EmptyStackException e){

    result = new Resource();

    _allocated.push(result);

    return result;

    }

    }

    代码4

    Resource getResource(){

    Resource result;

    if(_available.isEmpty()){

    result = new Resource();

    _allocated.push(reuslt);

    return result;

    }

    else{

    result = (Resource) _available.pop();

    _allocated.push(result);

    return result;

    }

    }

  • 相关阅读:
    C语言中指针*p[N], (*P)[N],及**p的区别
    一个酷炫的,基于HTML5,Jquery和Css的全屏焦点图特效,兼容各种浏览器
    day10函数作业详解
    day9函数作业详解
    day7计算作业详解
    day6作业详解
    通过Web安全工具Burp suite找出网站中的XSS漏洞实战(二)
    使用Docker快速部署ELK分析Nginx日志实践(二)
    java 字符串转运算符
    生成给定范围的n随机整数
  • 原文地址:https://www.cnblogs.com/kuyuyingzi/p/4266260.html
Copyright © 2011-2022 走看看