C++设计模式初探(二)

一、简单工厂模式

考虑这样一个场景,王者荣耀的英雄池里面有很多英雄类,当选择一个英雄的时候,就相当于实例化了一个类对象,比如 new 亚瑟new 妲己……传统的方法是在顶层直接调用 new+类名 来构造一个对象,但是如果类的构造过程十分复杂,而顶层逻辑并不关心具体的构造过程,就可以使用工厂模式。创建一个工厂类,其有一个create函数,根据传入的参数不同,返回不同的对象。

#include <iostream>
using namespace std;
//抽象英雄类
class AbstractHero
{
public:
    virtual void showName() {};
};

//百里守约类
class BaiLiShouYueHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "百里守约" << endl;
    };
};

//妲己类
class DaJiHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "妲己" << endl;
    };
};

//李白类
class LiBaiHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "李白" << endl;
    };
};

//工厂类
class Factory
{
public:
    AbstractHero* createHero(string name)
    {
        if (name == "百里守约")
        {
            return new BaiLiShouYueHero;
        }
        else if (name == "妲己")
        {
            return new DaJiHero;
        }
        else if (name == "李白")
        {
            return new LiBaiHero;
        }
        else
            return NULL;
    };
};

int main()
{
    Factory* factory = new Factory;
    AbstractHero* hero = factory->createHero("百里守约");
    hero->showName();
    delete hero;

    hero = factory->createHero("妲己");
    hero->showName();
    delete hero;

    hero = factory->createHero("李白");
    hero->showName();
    delete hero;
}

可见,工厂模式有以下优点:

1、逻辑层与底层解耦
2、客户端不必关心复杂的底层构造过程
3、适用于对象比较少的情况

缺点:

1、不符合开闭原则,增加一个英雄就要修改工厂类的代码
2、不符合单一职责原则,这个工厂类发生问题时候,会影响很多地方

二、工厂方法模式

简单工厂模式有弊端,即他不符合开闭原则和单一职责原则
那么只要设计一个抽象工厂类,再用 百里守约工厂类 ,李白工厂类,继承于抽象工厂类,这样就实现了工厂方法模式,也符合开闭原则和单一职责原则。
但毫无疑问,这种方法大大增加了代码量,增加抽象性和理解难度,这也是我最困惑的地方,这不累吗?

#include <iostream>
using namespace std;
//抽象英雄类
class AbstractHero
{
public:
    virtual void showName() {};
};

//百里守约类
class BaiLiShouYueHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "百里守约" << endl;
    };
};

//妲己类
class DaJiHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "妲己" << endl;
    };
};

//李白类
class LiBaiHero :public AbstractHero
{
public:
    virtual void showName() {
        cout << "李白" << endl;
    };
};

//抽象工厂类
class AbstractFactory
{
public:
    virtual AbstractHero* createHero()=0;
};

//百里守约工厂类
class BaiLiShouYueFactory :public AbstractFactory
{
public:
    AbstractHero* createHero()
    {
        return new BaiLiShouYueHero;
    };
};

//妲己工厂类
class DaJiFactory :public AbstractFactory
{
public:
    AbstractHero* createHero()
    {
        return new DaJiHero;
    };
};

//李白工厂类
class LiBaiFactory :public AbstractFactory
{
public:
    AbstractHero* createHero()
    {
        return new LiBaiHero;
    };
};

int main()
{
    AbstractFactory* factory = new BaiLiShouYueFactory;
    AbstractHero* hero = factory->createHero();
    hero->showName();
    delete hero;
    delete factory;

    factory = new DaJiFactory;
    hero = factory->createHero();
    hero->showName();
    delete hero;
    delete factory;

    factory = new LiBaiFactory;
    hero = factory->createHero();
    hero->showName();
    delete hero;
}
三、抽象工厂模式

考虑如下情景:
在前文中,我们已经创建了各种创建英雄的工厂,但一局游戏有十个人,玩家A选择的英雄,跟玩家B选择的英雄是不一样的,即使他们全部选择妲己,这几个妲己也是妲己A,妲己B……那怎么区分呢?
抽象工厂模式:针对产品族,而不是产品等级。
产品族:同一个来源,不同功能。如玩家A创建了妲己A,又创建了百里守约A。
产品等级:同一个功能,不同来源。如玩家A,玩家B创建了妲己A,妲己B。
抽象工厂,即把工厂作为抽象类,派生出玩家A工厂,玩家B工厂,这时如果新加入了玩家C,只需要再派生一个玩家C工厂即可,对于产品族的扩展,是符合开闭原则的;
但是对于产品等级则不符合开闭原则。假如要新增一个英雄露娜,就需要修改所有的工厂代码。
抽象工厂代码太多,就不放了,讲一讲思路。
1、抽象出一个抽象百里守约、抽象李白、抽象妲己类;
2、这三个类派生出玩家A的百里守约,玩家B的百里守约,玩家A的李白……等等
3、抽象出一个抽象工厂类;
4、派生出玩家A的工厂,玩家B的工厂。

四、单例模式

考虑如下情景:
在系统中,某些类只允许存在一个实例,比如任务管理器的窗口,只能有一个,这个情况就是单例模式。步骤如下:

1、构造函数私有化
2、声明一个静态私有成员变量,类型为该类
3、类外初始化该私有变量
4、提供一个静态的对外接口

#include <iostream>
using namespace std;
class Task
{
private:
    Task() {}

public:
    static Task *getInstance()
    {
        if (mTask == NULL)
        {
            mTask = new Task();
        }
        return mTask;
    }

private:
    static Task *mTask;
};

Task* Task::mTask = NULL;


int main()
{
    Task* p1 = Task::getInstance();
    return 0;
}

上面创建的是一个懒汉式单例,因为这个单例是在main函数执行之后才调用构造函数的,看起来比较懒,所以叫懒汉式,下面写一个饿汉式

class Task_hungry
{
private:
    Task_hungry() {}
	static Task_hungry* mTask;
public:
    static Task_hungry* getInstance()
    {
    	return mTask;
    }
};
Task_hungry* Task_hungry::mTask = new Task_hungry;

饿汉式的构造函数会在main之前就调用,看起来很饿,所以叫饿汉式
单例销毁问题:单例的一般不提供销毁接口。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值