我们有一个大型的遗留 C++/ObjC++ 应用程序,它可以从 Null Object 中受益,以取代数千个冗余检查:
Thing *thing=CurrentSelection();
if (thing) thing->Drill()
如果没有选择任何内容,则 CurrentSelection 返回 NotAThing 的实例
class NotAThing public: Thing
{
public:
virtual ~NotAThing(){}
virtual bool IsValid() const { return false;}
virtual void Drill() {}
};
我们可以摆脱几乎所有这些检查。对于一个包含很少客户端的类,Null Object 可能是一件好事。但是这个类无处不在;数十个课程依赖于它,并且有数千个检查。
我们可以逐步重构为Null 对象吗?
一种方法是重载 NotAThing 上的运算符以撒谎:
我们需要重载 !、!= 以及可能的转换为 bool 和 int。这仍然无法捕捉到明确的比较“thing==nil”。我已经可以听到 Scott Meyers ( Effective C++ ) 警告说这是疯狂的谎言。至少,这是一种代码味道。
而且,虽然我们可能会逐步退出其中的一些并依靠编译器来查找和删除不需要的 nil 测试,但我担心强制链会导致令人困惑和意外的结果——这是避免这些强制转换的原因之一。
另一方面,所有这些零检查。它们也是一种代码气味。
大规模重构空对象的智慧是什么?Fowler 和 Kerievsky 的机制很完善,但它们是为少数客户的课程设计的