• singleCall单来源调用解析及实现


    定义:

    单来源调用指一个类的生成工作只能由特定类来执行。

    eg李宁牌鞋子只能由李宁专卖店生产

    这个问题归结起来,也就是说在工厂模式中,指定的产品类只能通过具体的特定工厂类来生成,而不能自己new出来或者通过其他类生成。

    具体的,我们就在代码实现中进行说明了。

    这里我们来一步一步分析。

    首先,一个类实例(对象)不能自己产生,那么。我们就需要屏蔽构造函数了。

    那么,屏蔽了构造函数之后,如何获取一个实例呢。

    有两种方案可以实现。

    方案一:

    通过继承获取构造函数执行权限。如代码

    class base
    {
    protected:
        base()
        {
            Trace("");
        }
    };
    class driver:protected base
    {
    public:
        void test()
        {
            base b;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        driver d;
        d.test();
        return 0;
    }

    这个方案只是可以让一个类能够产生实例。单他和我们的意图严重偏离:

    a实例和子类的生命周期一致。

    b没有自主权。

    c其他类也可以模拟他的实现,继承父类获取生成权,这显然是个垃圾方案。

    方案二:类似单例模式方法处理

    产品类 构造函数屏蔽,但是提供一个获取实例的共有方法

    静态方法获取实例
    class base
    {
    protected:
        base()
        {
            Trace("");
        }
    public:
        static base* getInstance();
    };
    
    base* base::getInstance()
    {
        return new base();
    }
    int main(int argc, char const *argv[])
    {
        // base* p = new base();
        base * p = base::getInstance();
        return 0;
    }

    通过方案二,我们实现了一个类不能自己执行 base *p = new base()

    类型绑定

    那么下面我们的目标就是将这个产品类和具体可生产者进行绑定了。

    如何绑定呢,对于一个特定的类,处理之,我们就想到了this指针

    所以我们要做的就是,产品类构造函数依赖工厂类的this 指针

    // 通过静态方法获取,且依赖driver的this指针。
    // 但是此时也可以通过临时对象driver生成
    class driver;
    class base
    {
    protected:
        base()//driver*)
        {
            Trace("");
        }
    public:
        static base* getInstance(driver*);
    };
    
    base* base::getInstance(driver*)
    {
        return new base();
    }
    
    class driver
    {
    public:
        base* getInstance()
        {
            return base::getInstance(this);
        }
    };
    int main(int argc, char const *argv[])
    {
        
        base * p = (driver()).getInstance(); //我们所期望的运行方式。
        p = base::getInstance(new driver()); //产品类抓住漏洞强行生成自我
        return 0;
    }

    到这里,貌似我们的目标已经达到了,但是呢。如例子中的  p = base::getInstance(new driver());这个方法,本质还是base类自主生成的。

    并不能符合我们的要求。

    那么到这里,我们应该如何处理呢。

    我能想到的就是,不光让base建立依赖driver的this指针,同时设置权限。才能执行getinstace()

    首先给出最终代码了

    // 抽象接口类,提供子类行为,同时定义权限值以及权限判断给base中的getinstace方法使用
    class abstractDriver
    {
    protected:
        bool _canCreate;
        abstractDriver(bool can)
        :_canCreate(can)
        {}
    public:
        virtual bool canCreate(){
            return _canCreate;
        }
    };
    
    class base
    {
    protected:
        base()
        {
            Trace("");
        }
    public:
        static base* getInstance(abstractDriver*);
    };
    
    // 根据依赖的this对应类是否有权限执行决定生成
    base* base::getInstance(abstractDriver*dr)
    {
        if (dr->canCreate())
            /* code */
            return new base();
        else
            return NULL;
    }
    
    class driver:public abstractDriver
    {
    public:
        driver()
        :abstractDriver(false)
        {
            Trace("");
        }
        //在获取base实例前后修改权限。保证外部权限始终伪假
        base* getInstance()
        {
            _canCreate = true;
            base* p =base::getInstance(this);
            _canCreate = false;
            return p;
        }
    };
    
    int main(int argc, char const *argv[])
    {
        base* p = base::getInstance(new driver());
        cout << p <<endl;    //NULL,未生成实例
        p = (driver()).getInstance();
        cout << p <<endl;
        p = (driver()).getInstance();
        cout << p <<endl;
        return 0;
    }

    好了,最终的实现版本就完成了。

    符合我们的目标

    base类只能通过driver类生成。

    最后,我们可以发现,这个实现中的getInstace方法让我们想到了单例模式的实现。

    不同的是单例模式的结果是最终

    a只有一个类型实例产生,

    b生成方式可以是自主的 base::getinstance()

    而我们的单来源调用,

    a。生成实例个数不一定是一个,只是生成方式限定了

    b。不能通过直接调用base::getinstance()生成。

    之所以拿出来将两个模式进行比较,是因为:单来源调用并不是23种设计模式中的一种,初次看他时,我自己也是一脸蒙蔽。其次,两者都是很重要,很常用的方法。

    个人源码实现github地址:https://github.com/langya0/design_pattern_study/tree/master/singleCall

    23种设计模式C++实现及扩展代码:https://github.com/langya0/design_pattern_study

    参考《Single Call 模式

  • 相关阅读:
    MySQL concat函数的使用
    不懂技术的人请不要对懂技术的人说这很容易
    css常用样式属性详细介绍
    堆,栈,方法区,常量池,的概念
    Springboot整合 mybatis-generator
    探秘Java中的String、StringBuilder以及StringBuffer
    微信一键登录(微信OAuth2.0)
    ActiveMQ的作用总结(应用场景及优势)以及springboot+activeMq 实战
    SpringBoot几种定时任务的实现方式 和多线程执行任务
    如何使用RedisTemplate访问Redis数据结构
  • 原文地址:https://www.cnblogs.com/lang5230/p/5768292.html
Copyright © 2020-2023  润新知