《重构:改善既有代码的设计》 简化条件表达式  之 7 引入null对象  introduce null  object

《重构:改善既有代码的设计》中提到过很多重构方法,关于简化条件表达式的方法有8种。本文介绍:
引入null对象  introduce null  object

  • 名称:引入null对象  introduce null  object
  • 概要:检查某对象是否为null, 将null值替换为null对象
  • 动机: 更好的使用多态,而不必关心这是什么类型
  • 做法:
    • 为源类建立一个子类,使其行为就像时源类的null 版本。在源类和null子类中加上isNull()函数
    • 编译
    • 找出所有“索求源对象却获得一个null”的地方,修改这些地方,使他们改而获取一个空对象
    • 找出所有“将源对象与null做比较”的地方。修改这些地方,使它们调用isNull()函数。在“不该再出现null”的地方放上一些断言,确保null的确不再出现。
    • 编译,测试
    • 找出这样的程序点:如果对象不是null,做A动作,否则做B动作
    • 对于每一个上述地点,在null类中覆写A动作,使其行为和B动作相同
    • 使用上述被覆写的动作,然后删除“对象是否等于null”的条件测试。编译并测试。
  • 代码演示
    • 一家共用事业公司的系统以site表示地点,house和 apartment都使用该公司的服务。任何时候每个地点都拥有一个顾客。如果一个地点的顾客搬走了,新顾客还没有搬进来,此时这个地点就没有顾客。所以,必须保证customer的所有用户都能够处理“customer对象等于null”的情况。

修改之前的代码:

///.h
class BillingPlan
{
public:
    static BillingPlan * basic();
};
class PaymentHistory
{
public:
    int getWeeksDelingquentInLastYear();
};

class Customer
{
public:
    QString getName() const;
    BillingPlan* getPlan() const;
    PaymentHistory getHistory() const;

private:
    QString m_Name;
    BillingPlan *m_Plan;
    PaymentHistory m_History;
};
class Site
{
public:

    Customer *getCustomer() const;

private:
    Customer * m_customer;
};

///.cpp
Customer *Site::getCustomer() const
{
    return m_customer;
}

QString Customer::getName() const
{
    return m_Name;
}

BillingPlan* Customer::getPlan() const
{
    return m_Plan;
}

PaymentHistory Customer::getHistory() const
{
    return m_History;
}

int PaymentHistory::getWeeksDelingquentInLastYear()
{
    return 10;
}

BillingPlan *BillingPlan::basic()
{
    return new BillingPlan();
}
/main.cpp
Site site;
    Customer *customer = site.getCustomer();
    BillingPlan *plan;
    if (customer == nullptr)
        plan = BillingPlan::basic();
    else
        plan = customer->getPlan();
    QString customerName;
    if (customer == nullptr)
        customerName = "occupant";
    else
        customerName = customer->getName();
    int weeksDelinquent;
    if (customer == nullptr)
        weeksDelinquent = 0;
    else
        weeksDelinquent = customer->getHistory().getWeeksDelingquentInLastYear();

1)这个系统中可能有许多地方使用site和customer对象,它们都必须检查customer对象是否为nullptr,而这样的检查完全使重复的。
2)新建一个NullCustomer,并修改customer,使其支持“对象是否为null”的检查
3)加入一个工厂函数,专门用来创建NullCustomer对象。这样一来,用户就不必知道空对象的存在了。
4)对于所有“返回null”的地方,我都要将它改为“返回空对象”。
5) 设置 nullcustomer的getname()
修改之后的代码:

///.h
class BillingPlan
{
public:
    static BillingPlan * basic();
};
class PaymentHistory
{
public:
    int getWeeksDelingquentInLastYear();
};

class Customer
{
public:
    QString getName() const;
    BillingPlan* getPlan() const;
    PaymentHistory getHistory() const;
    bool isNull();
    static Customer * newNull();
protected:
    Customer();

private:
    QString m_Name;
    BillingPlan *m_Plan;
    PaymentHistory m_History;
};

class NullCustomer : public Customer
{
public:
    QString getName() const;
    bool isNull();
};

class Site
{
public:

    Customer *getCustomer() const;

private:
    Customer * m_customer;
};


///.cpp
Customer *Site::getCustomer() const
{
    return (m_customer == nullptr) ? Customer::newNull()  : m_customer;
}

QString Customer::getName() const
{
    return m_Name;
}

BillingPlan* Customer::getPlan() const
{
    return m_Plan;
}

PaymentHistory Customer::getHistory() const
{
    return m_History;
}

bool Customer::isNull()
{
    return false;
}

Customer *Customer::newNull()
{
    return new NullCustomer();
}

Customer::Customer()
{
    //needed by the NullCustomer
}

int PaymentHistory::getWeeksDelingquentInLastYear()
{
    return 10;
}

BillingPlan *BillingPlan::basic()
{
    return new BillingPlan();
}

QString NullCustomer::getName() const
{
    return "occupant";
}

bool NullCustomer::isNull()
{
    return  true;
}
///main.cpp
Site site;
    Customer *customer = site.getCustomer();
    BillingPlan *plan;
    if (customer->isNull())
        plan = BillingPlan::basic();
    else
        plan = customer->getPlan();
    QString customerName = customer->getName();
    //    if (customer->isNull())
    //        customerName = "occupant";
    //    else
    //        customerName = customer->getName();
    int weeksDelinquent;
    if (customer->isNull())
        weeksDelinquent = 0;
    else
        weeksDelinquent = customer->getHistory().getWeeksDelingquentInLastYear();

对于BillingPlan和PaymentHistory类,可以以设置null对象

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

giantmfc123

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值