常见设计模式

单例模式

类的构造函数如果都不是public访问属性,那么类的实例也是可以创建的。
单例模式就是这样,单例模式是一种常用的软件设计模式,其定义是单例对象的类只能允许一个实例存在。
网站的计数器,一般也是采用单例模式实现,如果你存在多个计数器,每一个用户的访问都刷新计数器的值,这样的话你的实计数的值是难以同步的。但是如果采用单例模式实现就不会存在这样的问题,而且还可以避免线程安全问题。同样多线程的线程池的设计一般也是采用单例模式,这是由于线程池需要方便对池中的线程进行控制。
步骤:构造函数私有化,提供一个全局的静态方法(全局访问点), 在类中定义一个静态指针,指向本类的变量的静态变量指针

class Singelton
{
private:
    Singelton()
    {
        cout << "Singelton 构造函数" << endl;
    }
public:
    static Singelton *getInstance()
    {
        if (p_Singel == NULL)//如果主函数中两次获得实例,返回的其实是同一个,地址都相同的。
        {
            lock();//为了避免两个线程在开始时同时调用getInstance的情况。
            p_Singel = new Singelton;
            unlock();
        }
        return p_Singel;
    }
    static void freeInstance()
    {
        if (p_Singel != NULL)
        {
            delete p_Singel;
            p_Singel = NULL;
        }
    }
private:
    static Singelton *p_Singel;
};

Singelton * Singelton::p_Singel = NULL;   //静态数据成员在类外初始化,注意初始化的时候不能再加static。只用加类型。

                                                                     静态常量成员可以在类内初始化,常量成员与静态成员都不能在类内初始化。

int main()

{

    Singelton *p = Singelton::getInstance();

    Singelton::freeInstance();

}

https://www.cnblogs.com/dupengcheng/p/7205527.html 单例模式详解。
现在,有两个文件,每个文件中都有一个 非局部静态全局对象,其中一个对象的创建需要另一个对象的辅助,但是,绝对无法控制不同被编译单元中非局部静态对象的初始化顺序。这个时候我们可以这样解决,类似于单例模式(其实就是单例模式),首先,把每个非局部静态对象转移到函数中,声明它为static。其次,让函数返回这个对象的引用。这样,用户将通过函数调用来指明对象。换句话说,用函数内部的static对象(局部)取代了非局部静态对象。

适配器模式

假设你们公司有最近收购了一家公司,两家公司都有各自的人员管理系统,两个系统都可以获取每一个员工的姓名。
你们公司系统中接口是:getName();
被收购公司系统中接口是:getPeopleName();
现在领导要求用我们公司的系统也可以查看新收购公司的人员信息。但是很明显二者接口不一样啊。此时适配器模式就有用了。

class CompanyA{
public:
    CompanyA(){}
    virtual void getName()
    {
        cout<<"get A name"<<endl;
    }
};
class CompanyB{
public:
    CompanyB(){}
    virtual void getPeopleName()
    {
        cout<<"get B name"<<endl;
    }
};
class Adapters:public CompanyA,private CompanyB//其实private继承也可以改成在class Adapters中添加一个private  CompanyB指针
{
public:
    Adapters()
    {}
    void getName()
    {
        CompanyA::getName();
        CompanyB::getPeopleName();
    }
};
int main()
{
    CompanyA* ca = new Adapters;
    ca->getName();
}

工厂模式

简单工厂模式

有两种产品,一个工厂能够生产这两种产品,客户要产品的时候,必须指明需要哪种产品,然后工厂去制造。
这种模式,如果想要增加产品,就要修改工厂类,这样违反了开闭原则(可以扩展,但是不能修改)。

class Product{
public:
    virtual void show() = 0;
};
class ProductA:public Product{
public:
    void show()
    {
        cout<<"Product A"<<endl;
    }
};
class ProductB:public Product{
public:
    void show()
    {
        cout<<"Product B"<<endl;
    }
};
class Factory{
public:
    Product* create(int numProduct)
    {
        switch (numProduct) {
        case 1:
            return new ProductA;
            break;
        case 2:
            return new ProductB;
            break;
        default:
            break;
        }
    }
};
int main()
{
    Factory f1,f2;
    f1.create(1)->show();
    f2.create(2)->show();
}

工厂方法模式

简单工厂模式,如果想要增加产品,就要修改工厂类,这样违反了开闭原则(可以扩展,但是不能修改)。
所谓工厂方法模式,是指定义一个用于创建对象的接口,让子类决定实例化哪一个类。现在有A、B两种产品,那么就开两个工厂。工厂A负责生产A产品,工厂B负责生产B产品。这时候客户不需要告诉共产生产哪种产品了,只需要告诉工厂生产就可以了。
这样,再一次增加产品的时候,只需增加一个产品类和一个工厂类就好了,不用去修改代码,只增加代码,符合开闭原则开闭原则(可以扩展,但是不能修改)。
但是,当A产品有两种型号A1、A2,B产品有两种型号B1、B2,工厂方法模式就无可奈何了,只能去修改A产品类、A工厂类、B产品类、B工厂类。

class Product{
public:
    virtual void show() = 0;
};
class ProductA:public Product{
public:
    void show()
    {
        cout<<"Product A"<<endl;
    }
};
class ProductB:public Product{
public:
    void show()
    {
        cout<<"Product B"<<endl;
    }
};
class Factory{
public:
    virtual Product* create() = 0;
};
class FactoryA:public Factory{
public:
    Product* create()
    {
        return new ProductA;
    }
};
class FactoryB:public Factory{
public:
    Product* create()
    {
        return new ProductB;
    }
};
int main()
{
    Factory *f1 = new FactoryA;
    Factory *f2 = new FactoryB;
    f1->create()->show();
    f2->create()->show();
}

抽象工厂模式(主要解决接口选择的问题)

当A产品有两种型号A1、A2,B产品有两种型号B1、B2,工厂方法模式就无可奈何了,只能去修改A产品类、A工厂类、B产品类。
此时需要抽象工厂模式,还是开设两家工厂,工厂A负责生产A1 、A2型号产品,B工厂负责生产B1、B2型号的产品。抽象工厂模式定义了抽象工厂类,工厂方法模式也定义了抽象工厂类,但是工厂方法模式的抽象工厂类只对应一个类型的子类,抽象工厂模式的抽象工厂类对应一系列类型的子类(多个create方法)这意味着抽象工厂模式更好的利用了工厂子类。 但是我们不去定义Product类,而改为定义1号产品类和2号产品类,若是再增加产品:
比如C1、C2,只需增加C1产品类和C2产品类,然后增加C工厂类。
如果增加了A3、B3产品,需要增加3号产品类,而且还需要修改工厂类的(不需要修改产品类,只增加)。这就是抽象工厂类的缺点。

class Product1{
public:
    virtual void show() = 0;
};
class ProductA1:public Product1{
public:
    void show()
    {
        cout<<"Product A1"<<endl;
    }
};
class ProductB1:public Product1{
public:
    void show()
    {
        cout<<"Product B1"<<endl;
    }
};
class Product2{
public:
    virtual void show() = 0;
};
class ProductA2:public Product2{
public:
    void show()
    {
        cout<<"Product A2"<<endl;
    }
};
class ProductB2:public Product2{
public:
    void show()
    {
        cout<<"Product B2"<<endl;
    }
};
class Factory{
public:
    virtual Product1* create1() = 0;
    virtual Product2* create2() = 0;
};
class FactoryA:public Factory{
public:
    Product1* create1()
    {
        return new ProductA1;
    }
    Product2* create2()
    {
        return new ProductA2;
    }
};
class FactoryB:public Factory{
public:
    Product1* create1()
    {
        return new ProductB1;
    }
    Product2* create2()
    {
        return new ProductB2;
    }
};
int main()
{
    Factory* f1 = new FactoryA;//生产A产品
    f1->create1()->show();
    f1->create2()->show();
    Factory* f2 = new FactoryB;//生产B产品
    f2->create1()->show();
    f2->create2()->show();
}

中介者模式

能都需要那些中介者的帮助,在地球上最大的中介者就是联合国了,它主要用来维护国际和平与安全、解决国际间经济、社会、文化和人道主义性质的问题。国与国之间的关系异常复杂,会因为各种各样的利益关系来结成盟友或者敌人,国与国之间的关系同样会随着时间、环境因为利益而发生改变。在我们软件的世界也同样如此,对象与对象之间存在着很强、复杂的关联关系,如果没有类似于联合国这样的“机构”会很容易出问题的。

对象与对象之间存在着大量的联系,导致系统结构变得复杂,如果一个对象改变,另一个对象也要跟着改变。而且系统的可扩展性低。增加一个新的对象,我们需要在其相关连的对象上面加上引用,这样就会导致系统的耦合性增高,使系统的灵活性和可扩展都降低。

如果两个类不必彼此通信,那么这两个类就不应当发生直接关联的关系。如果其中一个类需要调用另一个类中的方法,我们可以通过第三方来转发这个调用。所以对于关系比较复杂的系统,我们为了减少对象之间的关联关系,使之成为一个松耦合系统,我们就需要使用中介者模式。

以租房为例子,如果没有房屋中介,那么房客要自己找房东,而房东也要自己找房客,非常不方便。有了房屋中介机构就方便了,房东可以把要出租的房屋信息放到中介机构,而房客可以去中介机构咨询。在软件中,就是多个对象之间需要通信,如果没有中介,对象就需要知道其他对象,最坏情况下,可能需要知道所有其他对象,而有了中介对象就方便多了,对象只需与中介对象通信,而不用知道其他的对象。这就是中介者模式,下面以租房为例,给出中介者模式的UML图。

image.png

Person类 has a 中介者类,房屋中介者继承于中介者类,且房屋中介者has a 租房者、房东,租房者和房东继承于Person类。

如果再增加一个租房者或者房东,只需要在在增加一个Person子类,然后在中介者类中增加角色。

class Mediator;
class Person{
protected:
    Mediator* m_mediator;//中介类
public:
    virtual void setMediator(Mediator* mediator)//设置中介,意思是租房者或者房东要找的那个中介
    {}
    virtual void sendMessage(string message)//租房者或者房东向中介发送信息
    {}
    virtual void getMessage(string message)//从中介获取信息
    {}
};

class Mediator{
public:
    virtual void send(string message,Person* person)//person发送信息
    {}
    virtual void setA(Person* A)//设置其中一方
    {}
    virtual void setB(Person* B)//设置其中一方
    {}
};

class Renter:public Person{
public:
    void setMediator(Mediator* mediator)//租房者找中介
    {
        m_mediator = mediator;
    }
    void sendMessage(string message)
    {
        m_mediator->send(message,this);//租房者发送信息,然后中介通知房东接受信息
    }
    void getMessage(string message)
    {
        cout<<"Renter get a message:"<<message<<endl;
    }
};
class LandLord:public Person{
public:
    void setMediator(Mediator* mediator)//房东找中介
    {
        m_mediator = mediator;
    }
    void sendMessage(string message)
    {
        m_mediator->send(message,this);//房东发布信息,然后中介通知租房者接收
    }
    void getMessage(string message)
    {
        cout<<"LandLord get a message:"<<message<<endl;
    }
};

class HouseMediator:public Mediator{
private:
    Person* m_A;//租房者
    Person* m_B;//房东
public:
    void send(string message,Person* person)
    {
        if(person == m_A)//如果是租房者发布消息
        {
            m_B->getMessage(message);//房东接收消息
        }
        else//如果是房东发布消息
        {
            m_A->getMessage(message);//租房者接收消息
        }
    }
    void setA(Person* person)//房屋中介登记租房者
    {
        m_A = person;
    }
    void setB(Person* person)//房屋中介登记房东
    {
        m_B = person;
    }
};
int main()
{
    Mediator* mediator = new HouseMediator;
    Person* renter = new Renter;
    Person* landlord = new LandLord;

    mediator->setA(renter);//房屋中介登记租房者
    mediator->setB(landlord);//房屋中介登记房东

    renter->setMediator(mediator);//租房者找中介
    landlord->setMediator(mediator);//房东找中介
    //不管是房东还是租客,只要发布消息,就能传到中介,中介就能通知对方。
    renter->sendMessage("I want a house,50x50 and has a tolit");//租房者想要房子,房东通过中介能够get这个消息

    landlord->sendMessage("there is a house,80x80 and has a tolit");//房东想把房子租出去,租房者通过中介能够get这个消息
}

输出为:
LandLord get a message:I want a house,50x50 and has a tolit
Renter get a message:there is a house,80x80 and has a tolit

装饰器模式

装饰器模式能够实现动态地给对象添加功能。即从外部给对象添加相关职能。可以这样理解,比如说一个Person类,该类的操作有能吃、能睡、能跑、但假如随着人类的进化,某一天Person能飞了,能在水里游了等等,按照一般的写法是修改Person这个类,给这个类添加上能飞,能游等操作,但是这样破坏了面向对象的开放-封闭原则(对修改封闭,对拓展开发,有兴趣的可以查看相关文献),且随着人类的进化这个类就会变得越来越臃肿,越来越复杂,添加任何一个功能都必须对这个臃肿的类进行修改,出错的概率大大提升,且容易影响老功能,而装饰器模式可以解决这类问题,装饰器从外部给类添加职能,而不用去修改原始的类,拓展性好,可复用程度高。

[图片上传失败...(image-fa73bd-1560905916660)]

image.png
class Transform{//抽象具体类
public:
    virtual void move() = 0;
};
class Car:public Transform{//具体类
public:
    void move()
    {
        cout<<"I can move"<<endl;
    }
};
class Changer:public Transform{//抽象装饰器类
public:
    virtual void move() = 0;
protected:
    Transform* t;//抽象装饰器类 has a 抽象具体类
};
class Robot:public Changer{//具体装饰器类
public:
    Robot(Transform* tra)//传入抽象具体类
    {
        t = tra;
    }
    void move()//装饰具体类
    {
        t->move();
        cout<<"I can speak"<<endl;
    }
};
class Airplan:public Changer{//具体装饰器类
public:
    Airplan(Transform* tra)//传入抽象具体类
    {
        t = tra;
    }
    void move()//装饰具体类
    {
        t->move();
        cout<<"I can fly"<<endl;
    }
};
int main()
{
    Transform* t1 = new Car;
    t1->move();
    cout<<endl;
    Changer* c = new Airplan(t1);
    c->move();
}

代理模式

为某一个对象提供一个代理,代理控制对象的访问。

小林想追求小娟,但他不认识小娟。但他的朋友小王认识小娟,所以他通过让小王帮忙送礼物的方式追求小娟。

此时小王就是代理类,小林是RealSubject类,小王控制小林对小娟的访问。

[图片上传失败...(image-e35139-1560906028281)]

image.png
class Girl{
private:
    string name;
public:
    Girl(string name1)
    {
        name = name1;
    }
    string getName()
    {
        return name;
    }
};
class Givegift{
    virtual void GiveDolls() = 0;
    virtual void GiveFlowers() = 0;
    virtual void GiveChocolate() = 0;
};
class Puisuiter:public Givegift{
private:
    Girl* m_Girl;
    string name;
public:
    Puisuiter(string name1,Girl* mm)
    {
        name = name1;
        m_Girl = mm;
    }
    void GiveDolls()
    {
        cout<<name<<" Give money to "<<m_Girl->getName()<<endl;
    }
    void GiveFlowers()
    {
        cout<<name<<" Give flower to "<<m_Girl->getName()<<endl;
    }
    void GiveChocolate()
    {
        cout<<name<<" Give chocolate to "<<m_Girl->getName()<<endl;
    }
};
class Proxy:public Givegift{
private:
    Puisuiter* puisuiter;//代理类中 has a 真正的对象类,且代理类与真正的对象类都继承于“送礼物这个对象”。
public:
    Proxy(Puisuiter* p)
    {
        puisuiter = p;
    }
    void GiveDolls()
    {
        puisuiter->GiveDolls();
    }
    void GiveFlowers()
    {
        puisuiter->GiveFlowers();
    }
    void GiveChocolate()
    {
        puisuiter->GiveChocolate();
    }
};
int main()
{
    Girl* mm = new Girl("Ma Meng");
    Puisuiter* xiaolin = new Puisuiter("xiaolin",mm);
    Proxy* xiaowang = new Proxy(xiaolin);
    xiaowang->GiveDolls();
    xiaowang->GiveFlowers();
    xiaowang->GiveChocolate();
}

输出为:
xiaolin Give money to Ma Meng
xiaolin Give flower to Ma Meng
xiaolin Give chocolate to Ma Meng

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 215,634评论 6 497
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 91,951评论 3 391
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 161,427评论 0 351
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 57,770评论 1 290
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 66,835评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 50,799评论 1 294
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,768评论 3 416
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,544评论 0 271
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,979评论 1 308
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,271评论 2 331
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,427评论 1 345
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,121评论 5 340
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,756评论 3 324
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,375评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,579评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,410评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,315评论 2 352

推荐阅读更多精彩内容

  • 一、设计模式的起源 最早提出“设计模式”概念的是建筑设计大师亚力山大Alexander。在1970年他的《建筑的永...
    冰凡513阅读 346评论 0 0
  • 文章大纲 一、策略模式二、观察者模式三、工厂模式四、单例模式五、其他模式六、设计模式总结七、参考文章 一、策略模式...
    故事爱人c阅读 679评论 0 1
  • 1.设计模式六大原则 单一职责原则就一个类而言,应该仅有一个引起它变化的原因。例如,在 Activity 中不应该...
    zhangweiheb阅读 10,475评论 1 5
  • 分类 分三大类:创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。结构型模式,共七种...
    未闻花名未见你阅读 274评论 0 0
  • 在人与人的沟通当中,其实有好多信息,不仅仅是我们表面所表达的含义。所以我们常常会说话里有话,听话要听音。 而在这种...
    阎渝锦阅读 966评论 0 1