设计模式——空对象模式
定义
空对象模式(Null Object Pattern)是一种软件设计模式。在 C++ 中,它主要用于用一个空对象来代替 NULL 引用的检查。这个空对象可以提供默认的行为,从而避免了在代码中频繁地进行空指针(NULL)检查。
例如,在一个图形绘制系统中,如果没有指定图形的颜色,不是返回一个空指针(这会导致很多地方需要检查是否为空),而是返回一个表示 “无色” 的空对象,这个空对象有自己的默认行为,比如在绘制图形时不进行任何颜色相关的操作。
结构组成
- 抽象基类(Abstract Class):
定义了接口,这个接口包含了真实对象和空对象都需要实现的方法。例如,在一个文件读取系统中,抽象基类可能定义了read()和close()等方法,这些方法无论是对于真正的文件对象还是空文件对象都有意义。 - 真实对象类(Concrete Class):
实现了抽象基类中定义的接口,提供了真实的功能。继续以文件读取系统为例,真实对象类会实现read()方法来从文件中读取内容,close()方法来关闭文件。 - 空对象类(Null Class):
同样实现抽象基类的接口,但是它的方法实现通常是提供默认行为或者不执行任何操作。在文件读取系统中,空对象类的read()方法可能返回一个空字符串或者特定的错误码,表示没有读取到任何内容,close()方法可能什么都不做。
工作原理
当客户端代码请求一个对象的服务时,它不需要知道这个对象是真实对象还是空对象。空对象会按照其预定义的默认行为来响应请求,而真实对象则会执行实际的功能。
比如,在一个游戏角色系统中,角色有一个武器装备接口。如果角色没有装备武器,不是返回一个空指针,而是返回一个空武器对象。当游戏逻辑调用武器的 “攻击” 方法时,真实武器对象会执行攻击计算等操作,而空武器对象的 “攻击” 方法可能只是返回一个表示 “没有造成伤害” 的值或者打印一条 “没有武器,无法攻击” 的消息。
代码示例
首先是抽象基类,以汽车驾驶接口为例:
class CarDriveInterface {
public:
virtual void drive() = 0;
virtual void stop() = 0;
};
真实对象类,比如普通汽车类:
class NormalCar : public CarDriveInterface {
public:
void drive() override {
std::cout << "正常驾驶汽车。" << std::endl;
}
void stop() override {
std::cout << "汽车停止。" << std::endl;
}
};
空对象类:
class NullCar : public CarDriveInterface {
public:
void drive() override {
std::cout << "没有汽车,无法驾驶。" << std::endl;
}
void stop() override {
std::cout << "没有汽车,无需停止。" << std::endl;
}
};
客户端代码使用示例:
class CarOwner {
private:
CarDriveInterface* car;
public:
CarOwner(CarDriveInterface* c) : car(c) {}
void driveCar() {
car->drive();
}
void stopCar() {
car->stop();
}
};
在main函数中使用:
int main() {
CarDriveInterface* normalCar = new NormalCar();
CarOwner owner1(normalCar);
owner1.driveCar();
owner1.stopCar();
CarDriveInterface* nullCar = new NullCar();
CarOwner owner2(nullCar);
owner2.driveCar();
owner2.stopCar();
return 0;
}
在这个例子中,CarOwner类不需要判断它持有的car对象是真实汽车还是空汽车,因为空汽车对象已经有了自己的默认行为。
优点
- 减少空指针检查:
可以使代码更加简洁,减少了大量的空指针检查逻辑。在复杂的系统中,如果到处都需要检查对象是否为 NULL,代码会变得很杂乱,使用空对象模式可以避免这种情况。 - 提高代码可读性和可维护性:
代码的逻辑更加清晰,因为不需要频繁地处理特殊的空情况。例如,在一个员工管理系统中,如果没有员工对象就返回一个空对象,而不是 NULL,其他模块在调用员工相关的方法(如 “工作”“休息” 等)时,不需要复杂的空指针检查,直接调用方法即可,代码的可读性得到了提高。 - 增强代码的健壮性:
降低了因为空指针引用而导致程序崩溃的风险。即使在某些情况下对象不存在或者没有初始化,空对象的默认行为也可以让程序继续稳定地运行,而不是因为空指针异常而终止。
缺点
- 增加类的数量:
需要创建一个额外的空对象类,对于简单的系统来说,这可能会使代码看起来有些臃肿。如果有很多不同类型的对象都需要空对象模式,会导致类的数量显著增加。 - 可能隐藏错误:
如果空对象的默认行为没有设计好,可能会掩盖一些本应该被发现的错误。例如,在一个计算系统中,如果空对象的计算方法总是返回 0,可能会导致用户误以为计算是正确的,而实际上是因为使用了空对象而没有进行真正的计算。
原文地址:https://blog.csdn.net/chuliling0446/article/details/144006017
免责声明:本站文章内容转载自网络资源,如本站内容侵犯了原著者的合法权益,可联系本站删除。更多内容请关注自学内容网(zxcms.com)!