单例模式

确保对象的唯一性.

饿汉模式,提前创建好, 比如静态定义.即在对象创建前,该对象就创建好了, 但是对象特别大时,可能耗费时间,不是很有必要.

懒汉模式,第 1 次调用时,才 new.下面是一个经典的双重check锁定+饿汉的单例:


//.h
public
    static timerRunner* getInstance(void);
private:
    static pthread_mutex_t mutex;
    static timerRunner* m_instance;
...

//.c
pthread_mutex_t timerRunner::mutex = PTHREAD_MUTEX_INITIALIZER;
timerRunner* timerRunner::m_instance = NULL;

timerRunner* timerRunner::getInstance(void)
{
    if(NULL == m_instance) {
        pthread_mutex_lock(&mutex);
        if(NULL == m_instance) {
            m_instance = new timerRunner(128);
        }
        pthread_mutex_unlock(&mutex);
    }
    return m_instance;
}

还有一种更好的单例模式,Initialization on Demand Holder(IoDH)

实现方式是单例类里,再增加一个静态内部类,,静态内部类创建单例对象再返回;好在哪里?并不太明白.

简单工厂

把 new productA, new productB…封装在一个 factory 对象里,由 factory 统一管理对象的 new,使用者不关心怎么 new 出对象;

对外的接口类似:

proFactory::get_product(string p)
{
    if p == string("A")
        return new productA();
    if p == string("B")
        return new productB();
    ...
}

factory = new proFactory();
productA = factory.get_product("A");
productA = factory.get_product("B");
...

当然 get_product 也可以是静态方法.

productA = proFactory().get_product("A");
productB = proFactory().get_product("B");
...

在实际要使用 product 的类里,注意对象的职责问题, 即对象的创建和对象的使用分离,尽量不要放在一个类里,否则,当对象需要改变时,又得修改类,违背开闭原则.

对象的职责是指: 谁创建对象, 对象本身可以做什么, 谁使用对象

经典的使用简单工厂的例子:

class product {
    virtual const string & name() = 0
}
class productA : public Product {
    // 实现自己的name
};
class productB : public Product {
    // 实现自己的name
};

class Store {
    private:
        Product * mp;
    public:
        //不是具体的product,而是用product的基类, 结合工厂模式
        void set_product(string name) {
            mp =  proFactory().get_product(name);
        }
        show_product_name() {
            return mp->name();
        }
};

工厂方法 (多态工厂模式)

如果简单工厂的工厂本身复杂,而且工厂创建的对象也很多,很复杂,那么再次将工厂抽象掉是个很自然的想法.每一个或者一类的产品的创建对应一个抽象工厂的派生工厂.

2018-08-01-16-12-00

class foodFactory : public  Factory {...}
class clothFactory : public  Factory {...}

class Store: public {
    Factory  factory;
    public:
        void produce() {
            //food工厂new出fish
            factory =  foodFactory();
            fish  =  factory.get_product("fish");
            //cloth工厂new出pants
            factory =  clothFactory();
            pants =  factory.get_product("pants");
        }
}
...

进一步的,将实际的工厂,产品的具体名字配置到配置文件里, 灵活性就大大增加了. 从普通角度,自然可以读取文件,用if...else提前把代码写好,但是一旦新增工厂,还得改代码. java 里的反射机制, 从类名创建出对象, 只用新增一个工厂类以及实现就好了,符合开闭原则.

重载的工厂方法

重载实现的更多的生产对象的生产方法(就是 get_product 的不同参数),满足更多的需求.

    class foodFactory : public  Factory {
        public:
            Product * get_product(string name);
            //重载的工厂方法
            Product * get_product(string path);
            Product * get_product(date date);
    }

抽象工厂模式

可以理解为工厂的组合,每个工厂对应具体的产品,不同的工厂实现,就是不同的组合,也就是不同的产品族.

class peopleFactory {

    virtual Product* get_cloth() = 0;
    virtual Product* get_food() = 0;
    virtual Product* get_glass() = 0;
}

class AisaPeopleFactory : public peopleFactory {
    Product* get_cloth() {return new AisaCloth();}
    Product* get_food() {return new AisaFood();}
    Product* get_glass() {return new Aisaglass();}
}

class AfricaPeopleFactory : public peopleFactory {
    Product* get_cloth() {return new AfricaCloth();}
    Product* get_food() {return new AfricaFood();}
    Product* get_glass() {return new AfricaGlass();}
}

切换一个抽象工厂时,就切换了一个产品族.

书上的是讲 UI 换皮肤,也是很生动的例子.

原型模式

就是对象的拷贝,java 里的 clone,类似的 c++里的深拷贝

// = 要求是做了深拷贝实现, 对应java里的Cloneable接口的实现
 Object old("some paras");
 auto new = old;

皮一点,也可以给自己的类增加一个clone()方法,实现深拷贝就好.

建造者模式