二阶构造设计模式

发布时间:2024年01月14日

目录

构造函数回顾

深入思考

实验

构造函数的真相

半成品对象

引入二阶构造设计模式

设计理念

二阶构造设计模式图

二阶构造示例

完整demo

小结


构造函数回顾

  1. 类的构造函数用于对象的初始化。
  2. 构造函数与类同名并且没有返回值。
  3. 构造函数在对象定义时自动被调用

深入思考

  1. 如何判断构造函数的执行结果?
  2. 在构造函数中执行 return 语句会发生什么?
  3. 构造函数执行结束是否意味着对象构造成功?

实验

test.cpp

#include <stdio.h>

class Test
{
    private:
        int mi;
        int mj;
    public:
        Test(int i,int j)
        {
            mi=i;
            mj=j;
        }
        
        int getI()
        {
            return mi;
        }
        
        int getJ()
        {
            return mj;
        }
};

int main()
{
    Test t1(1,2);
    
    printf("t1.mi = %d\n",t1.getI());
    printf("t1.mj = %d\n",t1.getJ());
    
    return 0;
}

编译运行,实验结果符合预期。

delphi@delphi-vm:~/c_c++$ g++ test.cpp -o test.out
delphi@delphi-vm:~/c_c++$ ./test.out 
t1.mi = 1
t1.mj = 2

接下来在构造函数中,加入 return语句,实验结果如下所示:

test.cpp

#include <stdio.h>

class Test
{
    private:
        int mi;
        int mj;
    public:
        Test(int i,int j)
        {
            mi=i;
            return ;
            mj=j;
        }
        
        int getI()
        {
            return mi;
        }
        
        int getJ()
        {
            return mj;
        }
};

int main()
{
    Test t1(1,2);
    
    printf("t1.mi = %d\n",t1.getI());
    printf("t1.mj = %d\n",t1.getJ());
    
    return 0;
}

编译运行,实验结果如下,可以看到 mj的值为随机数了。

delphi@delphi-vm:~/c_c++$ g++ test.cpp -o test.out
delphi@delphi-vm:~/c_c++$ ./test.out 
t1.mi = 1
t1.mj = 12783604

以上结果,可以看到:构造函数出现问题了,但是对象依旧诞生了,那么这个对象是一个合法的对象吗?

构造函数的真相

  1. 构造函数只提供自动初始化成员变量的机会。
  2. 构造函数不能保证初始化逻辑一定会成功。
  3. 执行 return 语句后构造函数立即结束。
  4. 构造函数能决定的只是对象的初始状态,而不能决定对象是否诞生。

半成品对象

  1. 初始化操作不能按照预期完成而得到的对象。
  2. 半成品对象是合法的C++对象,也是Bug的重要来源。

引入二阶构造设计模式

设计理念

工程开发中的构造过程可以分为:

? ? ? ? 一:资源无关的初始化操作

? ? ? ? ? ? ? ? 不可能出现异常情况的操作

? ? ? ? 二:需要使用系统资源的操作

? ? ? ? ? ? ? ? 可能出现异常情况,如:内存申请,访问文件

二阶构造设计模式图

从设计层面,将构造过程一分为二,第一阶段的构造做资源无关的操作,第二阶段做资源申请的操作。用二阶设计模式要么产生一个完整合法的C++对象,要么直接返回NULL,不会产生一个半成品的C++对象。

二阶构造示例

class TwoPhaseCons
{
    private:
        TwoPhaseCons(){  //第一阶段的构造函数
               
        }
        
        bool construct(){ //第二阶段的构造函数
        
        }
    public:
        static TwoPhaseCons* NewInstance(); //创建对象函数
};

TwoPhaseCons* TwoPhaseCons::NewInstance()
{
    TwoPhaseCons* ret = new TwoPhaseCons();
    
    //如果第二阶段构造失败,返回NULL
    if(!(ret && ret->construct()))
    {
        delete ret;
        ret = NULL;
    }
    
    return ret;
}

完整demo

#include <stdio.h>


class TwoPhaseCons
{
    private:
        TwoPhaseCons()   //第一阶段的构造函数
        {  
             //做资源无关的初始化的操作
        }
        
        bool construct()  //第二阶段的构造函数
        { 
             //做内存申请、打开文件的操作
            
             return true;
        }
    public:
        static TwoPhaseCons* NewInstance(); //创建对象函数
};

TwoPhaseCons* TwoPhaseCons::NewInstance()
{
    TwoPhaseCons* ret = new TwoPhaseCons();
    
    //如果第二阶段构造失败,返回NULL
    if(!(ret && ret->construct()))
    {
        delete ret;
        ret = NULL;
    }
    
    return ret;
}

int main(int argc,char* argv[])
{
    TwoPhaseCons* obj = TwoPhaseCons::NewInstance();
    
    printf("obj = %p\n",obj);
    
    
    delete obj;
    
    return 0;
}


小结

  1. 构造函数只能够决定对象的初始化状态。
  2. 构造函数中初始化操作的失败不影响对象的诞生。
  3. 初始化不完全的半成品对象是Bug的重要来源。
  4. 二阶构造人为的将初始化过程分为两部分。
  5. 二阶构造能够确保创建的对象都是完整初始化的。

文章来源:https://blog.csdn.net/weixin_42136255/article/details/135577019
本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。