设计模式之空对象模式

目录

1.简介

2.结构图

3.实例

4.优缺点


1.简介

        空对象模式也是我们平时编程用的比较多的一种行为型设计模式,它的宗旨在解决空对象引起的异常报错问题;在空对象模式(Null Object Pattern)中,一个空对象取代 Null 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。这样的 Null 对象也可以在数据不可用的时候提供默认的行为。

        在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。

        在C/C++编程中,如果一个接口返回一个对象指针,如:

    class AbstractObject{public:int compareTo(int value){//...return 0;}}AbstractObject* getValue(int n);

在接口调用的时候,IMessageField*  p =  getValue(100); 一般都是去判断 p 是否 为null,如果不判断p, 直接调用IMessageField的成员函数compareTo,程序就崩溃了;利用空对象模式就解决了这个问题,从而避免不管怎么调用都不会导致程序崩溃的情况,下面我们就看看怎么解决这个问题的。

2.结构图

空对象模式的UML类图如下:

由上图可以看到,空对象模式主要包含3个角色。
1) 抽象对象(AbstractObject):定义所有子类公有的行为和属性,一般定义一个isNull接口是不必可少的。
2) 真实对象(CRealObject):继承AbstractObject类,并实现所有行为。
3) 空对象(CNullObject):继承AbstractObject类,对父类方法和属性不做实现和赋值。

3.实例

真实对象和空对象定义如下:

#include <iostream>
#include <map>
#include <memory>// 抽象对象
class AbstractObject {
public:virtual void doSomething() = 0;virtual bool isNull() const = 0;
};// 真实对象1
class CRealObject1 : public AbstractObject {
public:void doSomething() override {std::cout << "CRealObject1 is doing something." << std::endl;}bool isNull() const override { return false; }
};// 真实对象2
class CRealObject2 : public AbstractObject {
public:void doSomething() override {std::cout << "CRealObject2 is doing something." << std::endl;}bool isNull() const override { return false; }
};// 真实对象3
class CRealObject3 : public AbstractObject {
public:void doSomething() override {std::cout << "CRealObject3 is doing something." << std::endl;}bool isNull() const override { return false; }
};// 空对象
class CNullObject : public AbstractObject {
public:void doSomething() override {// 空对象不进行任何操作}bool isNull() const override { return true; }
};class CMessageEntity
{
public:void  add(int value, AbstractObject* pObject) {m_objects[value] = pObject;}void  remove(int value) {m_objects.erase(value);}AbstractObject* getObject(int value) {static CNullObject s_nullObject;if (m_objects.find(value) != m_objects.end()) {return m_objects[value];}return &s_nullObject;}
private:std::map<int, AbstractObject*> m_objects;
};

测试例程如下:

int main() {std::unique_ptr<AbstractObject> obj1(new CRealObject1());std::unique_ptr<AbstractObject> obj2(new CRealObject2());std::unique_ptr<AbstractObject> obj3(new CRealObject3());CMessageEntity entities;entities.add(10, obj1.get());entities.add(20, obj2.get());entities.add(234, obj3.get());entities.getObject(20)->doSomething();  // 输出: CRealObject2 is doing something.entities.getObject(234)->doSomething(); // 输出: CRealObject3 is doing something.entities.getObject(0)->doSomething();   // 输出: entities.getObject(10)->doSomething();  // 输出: CRealObject1 is doing something.return 0;
}

上述示例中,定义了一个抽象对象类AbstractObject,真实对象类CRealObject1、CRealObject2、CRealObject3和空对象类CNullObject都继承自抽象对象类。在主函数中,创建了三个真实对象和一个空对象,并调用它们的doSomething()方法。真实对象会执行具体的操作,而空对象不进行任何操作。通过使用空对象,可以避免对空值的检查,使得代码更加简洁和健壮。

4.优缺点

优点:
1.避免NullPointerException:这是空对象模式最主要的好处。通过提供一个空对象实例,可以避免在调用方法时抛出NullPointerException
2.改善代码质量:通过明确地表示一个对象是空的,可以使代码更具可读性,也减少了因为错误地使用空引用而导致的运行的错误。
3.更好的扩展性:如果一个类经常需要一个空实例,那么在将来需要改变这个类的行为时,可以更容易地适应这些变化
缺点:
1增加类的数量:为了使用空对象模式,口能需要为每一个类都提供一个空对象实现,这会增加类的数量,也可能会增加代码的复杂性。
2.不易发现错误:有时候,开发者可能会错误地认为空对象实例表示正常的操作,这可能导致在运行时出现难以发现的错误。
3.违反开放封闭原则:开放封闭原则鼓励的是添加新的行为,而不是新的具体类。而空对象模式需要为每个类添加新的空实现类,这似乎与开放封闭原则相违背。

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.rhkb.cn/news/237750.html

如若内容造成侵权/违法违规/事实不符,请联系长河编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

【数据库】聊聊MVCC机制与BufferPool缓存机制

上一篇文章&#xff0c;介绍了隔离级别&#xff0c;MySQL默认是使用可重复读&#xff0c;但是在可重复读的级别下&#xff0c;可能会出现幻读&#xff0c;也就是读取到另一个session添加的数据&#xff0c;那么除了配合使用间隙锁的方式&#xff0c;还使用了MVCC机制解决&#…

企业级大数据安全架构(三)修改集群节点hostname

作者&#xff1a;楼高 在后续安装FreeIPA的过程中&#xff0c;要求机器名必须包含完整的域名信息。如果之前在Ambari集群节点上的机器名不符合这个要求&#xff0c;可以按照以下步骤在Ambari上修改所有节点的机器名&#xff1a; 1.部署节点说明 本次测试是三台 ambari 节点&…

迅为RK3568开发板Android11/12/Linux编译驱动到内核

在平时的驱动开发中&#xff0c;经常需要在内核中配置某种功能&#xff0c;为了方便大家开发和学习&#xff0c;本小 节讲解如何在内核中添加驱动。具体的讲解原理讲解请参考本手册的驱动教程。 Android11 源码如果想要修改内核&#xff0c;可以运行以下命令进行修改: cd ke…

reactNative0.71版本的使用

开发环境配置 参考reactNative 官网 版本选中0.71 打包配置 1. IOS 打开项目 -> 进入ios目录->执行命令 pod install ->项目名称.xcworkspace -> 使用xcode打开->配置证书 证书配置截图如下 &#x1f4a1;tips&#xff1a;TARGETS目录下会有多个文件&#x…

计算机图形学流体模拟 blender 渲染脚本

做流体模拟的时候&#xff0c;想要复现别人的成果&#xff0c;但是别人的代码都是每帧输出 ply 格式的文件&#xff0c;渲染部分需要自己完成 看了一下&#xff0c;似乎用 blender 是最简单的&#xff0c;于是记录一下过程中用到的代码 Blender 版本 4.0 批量导入 ply 假设…

Hyperledger Fabric 通道配置文件解析

fabric 版本 v2.4.1 Fabric 网络是分布式系统&#xff0c;采用通道配置&#xff08;Channel Configuration&#xff09;来定义共享账本的各项行为。通道配置的管理对于网络功能至关重要。 通道配置一般包括通道全局配置、排序配置和应用配置等多个层级&#xff0c;这些配置都存…

在生产环境中使用uWSGI来运行Flask应用

安装uwsgi pip install uwsgi -i https://pypi.tuna.tsinghua.edu.cn/simple安装不上则使用以下命令&#xff1a; conda install -c conda-forge uwsgi 当您成功安装uwsgi后&#xff0c;您可以通过以下步骤来测试uwsgi是否安装成功&#xff1a; 创建一个Python脚本&#xff…

Oracle11.2.0.4从RMAN备份中快速恢复单个表的方法

文章目录 前言一、查询所要恢复的表所涉及的表空间二、创建用于恢复的数据库三、恢复步骤1.恢复控制文件2.修改redo日志名称3.表空间恢复4.表空间recover5.查询数据 前言 由于用户误操作导致某表中的数据错乱&#xff0c;导致业务不能正常使用&#xff0c;现需要将该表恢复到一…

软件测试|MySQL BETWEEN AND:范围查询详解

简介 在MySQL数据库中&#xff0c;使用BETWEEN AND操作符可以进行范围查询&#xff0c;即根据某个字段的值在指定范围内进行检索数据。这个操作符非常有用&#xff0c;因为它可以让我们轻松地筛选出位于两个特定值之间的数据&#xff0c;而不需要使用复杂的条件语句。 BETWEE…

[足式机器人]Part2 Dr. CAN学习笔记-Advanced控制理论 Ch04-8 状态观测器设计 Linear Observer Design

本文仅供学习使用 本文参考&#xff1a; B站&#xff1a;DR_CAN Dr. CAN学习笔记-Advanced控制理论 Ch04-8 状态观测器设计 Linear Observer Design

金融帝国实验室(Capitalism Lab)V10版本游戏平衡性优化与改进

即将推出的V10版本中的各种游戏平衡性优化与改进&#xff1a; ————————————— 一、当玩家被提议收购一家即将破产的公司时&#xff0c;显示商业秘密。 当一家公司濒临破产&#xff0c;玩家被提议收购该公司时&#xff0c;如果玩家有兴趣评估该公司&#xff0c;则无…

鸿蒙开发-UI-布局

鸿蒙开发-序言 鸿蒙开发-工具 鸿蒙开发-初体验 鸿蒙开发-运行机制 鸿蒙开发-运行机制-Stage模型 鸿蒙开发-UI 鸿蒙开发-UI-组件 鸿蒙开发-UI-组件-状态管理 鸿蒙开发-UI-应用-状态管理 鸿蒙开发-UI-渲染控制 文章目录 前言 一、布局概述 1.布局结构 2.布局元素组成 3.布局分类 …

【数据结构】树和二叉树堆(基本概念介绍)

&#x1f308;个人主页&#xff1a;秦jh__https://blog.csdn.net/qinjh_?spm1010.2135.3001.5343&#x1f525; 系列专栏&#xff1a;《数据结构》https://blog.csdn.net/qinjh_/category_12536791.html?spm1001.2014.3001.5482 ​​ 目录 前言 树的概念 树的常见名词 树与…

【RV1126 学习】SDK/ U-Boot/kernel/rootfs 编译学习

文章目录 RV1126芯片介绍rv1126 模块代码目录相关说明 SDK 包下的脚本使用build.sh 脚本使用envsetup.sh 脚本使用mkfirmware.sh 脚本使用rkflash.sh 脚本使用 U-Boot 编译和配置uboot 的配置修改编译操作 kernel 的修改编译rootfs 编译和配置buildroot 配置busybox 配置 固件打…

MySQL主从复制配置(双主双从)

一、架构规划 一主多从可以缓解读的压力&#xff0c;但是如果主宕机了&#xff0c;所有从都不能写了&#xff0c;因此我们配置双主双从。 1、规划图 master1和master2互为主从关系&#xff0c;slave1是master1的从&#xff0c;slave2是master2的从。 2、环境准备 准备四台机…

LeetCode-1822/1502/896/13

1.数组元素积的符号&#xff08;1822&#xff09; 题目描述&#xff1a; 已知函数 signFunc(x) 将会根据 x 的正负返回特定值&#xff1a; 如果 x 是正数&#xff0c;返回 1 。 如果 x 是负数&#xff0c;返回 -1 。 如果 x 是等于 0 &#xff0c;返回 0 。 给你一个整数数组…

c++多久会被Python或者新语言取代?

c多久会被Python或者新语言取代&#xff1f; 在开始前我有一些资料&#xff0c;是我根据网友给的问题精心整理了一份「c的资料从专业入门到高级教程」&#xff0c; 点个关注在评论区回复“888”之后私信回复“888”&#xff0c;全部无偿共享给大家&#xff01;&#xff01;&am…

多传感器融合SLAM数学学习历程

多传感器融合SLAM数学学习历程 >>> 流形和流形空间&#xff08;姿态&#xff09; https://blog.csdn.net/professor_Xie/article/details/131911894 fast-lio 带着问题 看知识 欧式空间和流形空间的区别和联系? 基本结构&#xff1a;欧式空间是我们熟悉的传统三维…

机器学习笔记:时间序列异常检测

1 异常类型 1.1 异常值outlier 给定输入时间序列&#xff0c;异常值是时间戳值其中观测值与该时间序列的期望值不同。 1.2 波动点&#xff08;Change Point&#xff09; 给定输入时间序列&#xff0c;波动点是指在某个时间t&#xff0c;其状态在这个时间序列上表现出与t前后…

jmeter如何做接口测试?

Jmeter介绍&测试准备&#xff1a; Jmeter介绍&#xff1a;Jmeter是软件行业里面比较常用的接口、性能测试工具&#xff0c;下面介绍下如何用Jmeter做接口测试以及如何用它连接MySQL数据库。 前期准备&#xff1a;测试前&#xff0c;需要安装好Jmeter以及jdk并配置好jdk环…