ZhangJie Software Development Engineer

设计模式

2023-07-22
ZhangJie

设计模式。

单例模式

保证一个类、只有一个实例存在,同时提供能对该实例加以访问的全局访问方法。

实现单例步骤常用步骤:

  • 构造函数私有化
  • 提供一个全局的静态方法(全局访问点)
  • 在类中定义一个静态指针,指向本类的变量的静态变量指针

饿汉式单例和懒汉式单例

  • 懒汉式
#include <iostream>
using namespace std;

class Singelton
{
private:
    Singelton() {
        printf("Singelton()...\n");
    }

public:
    static Singelton* getInstance() {
        if (singel_ == NULL) { // 懒汉式:1. 每次获取实例都要判断; 2. 多线程会有问题。
            singel_ = new Singelton;
        }
        return singel_;
    }
    static int getCount() {
        return count_;
    }

private:
    static Singelton* singel_;
    static int count_;
};

Singelton* Singelton::singel_ = NULL; // 懒汉式并没有创建单例对象
int Singelton::count_ = 0;

int main()
{
    Singelton* p1 = Singelton::getInstance();
    Singelton* p2 = Singelton::getInstance();

    if (p1 == p2) {
        printf("p1和p2是同一个对象!\n");
    }
    else {
        printf("p1和p2不是同一个对象!\n");
    }

    return 0;
}
  • 饿汉式
#include <iostream>
using namespace std;

class Singelton
{
private:
    Singelton() {
        printf("Singelton()...\n");
    }
    ~Singelton()
    {
        printf("~Singelton()...\n");
    }

public:
    static Singelton* getInstance() {
        return singel_;
    }
    static void freeInstance() {
        if (singel_ != NULL) {
            delete singel_;
            singel_ = NULL;
        }
    }
    static int getCount() {
        return count_;
    }

private:
    static Singelton* singel_;
    static int count_;
};


Singelton* Singelton::singel_ = new Singelton; // 饿汉式不管你创不创建实例,均把实例new出来
int Singelton::count_ = 0;

int main()
{
    Singelton* p1 = Singelton::getInstance();
    Singelton* p2 = Singelton::getInstance();

    if (p1 == p2) {
        printf("p1和p2是同一个对象!\n");
    }
    else {
        printf("p1和p2不是同一个对象!\n");
    }

    Singelton::freeInstance();
}

简单工厂模式

通过专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。

模式中包含的角色及其职责

  • 工厂(Creator)角色

简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。

  • 抽象(Product)角色

简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

  • 具体产品(Concrete Product)角色

简单工厂模式所创建的具体实例对象。

简单工厂模式的优缺点

在这个模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在使用时可以直接根据工厂类去创建所需的实例,而无需了解这些对象是如何创建以及如何组织的。有利于整个软件体系结构的优化。不难发现,简单工厂模式的缺点也正体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,所以“高内聚”方面做的并不好。另外,当系统中的具体产品类不断增多时,可能会出现要求工厂类也要做相应的修改,扩展性并不很好。

//思想:核心思想是用一个工厂,来根据输入的条件产生不同的类,然后根据不同类的virtual函数得到不同的结果。
//元素分析:
//抽象产品类:水果类
//具体的水果了:香蕉类、苹果类、梨子
//优点适用于不同情况创建不同的类时
//缺点客户端必须要知道基类和工厂类,耦合性差增加一个产品,需要修改工厂类

#include <iostream>
using namespace std;

class Fruit
{
public:
    virtual void getFruit() = 0;
};

class Banana : public Fruit
{
public:
    virtual void getFruit() {
        cout << "banana\n";
    }
};

class Apple : public Fruit
{
public:
    virtual void getFruit() {
        cout << "apple\n";
    }
};

class Factory
{
public:
    static Fruit* create(const char* name) {
        Fruit* fruit = NULL;
        if (strcmp(name, "apple") == 0) {
            fruit = new Apple();
        }
        else if (strcmp(name, "banana") == 0) {
            fruit = new Banana();
        }
        return fruit;
    }
};

int main()
{
    Fruit* fruit = Factory::create("apple");
    if (fruit) {
        fruit->getFruit();
    }
    delete fruit;

    fruit = Factory::create("banana");
    if (fruit) {
        fruit->getFruit();
    }
    delete fruit;
    
    return 0;
}

工厂模式

工厂方法模式同样属于类的创建型模式又被称为多态工厂模式。工厂方法模式的意义是定义一个创建产品对象的工厂接口,将实际创建工作推迟到子类当中。

核心工厂类不再负责产品的创建,这样核心类成为一个抽象工厂角色,仅负责具体工厂子类必须实现的接口,这样进一步抽象化的好处是使得工厂方法模式可以使系统在不修改具体工厂角色的情况下引进新的产品。

  • 抽象工厂(Creator)角色

工厂方法模式的核心,任何工厂类都必须实现这个接口。

  • 具体工厂( Concrete Creator)角色

具体工厂类是抽象工厂的一个实现,负责实例化产品对象。

  • 抽象(Product)角色

工厂方法模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。

  • 具体产品(Concrete Product)角色。

工厂方法模式所创建的具体实例对象

工厂方法模式和简单工厂模式比较

工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。 工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。 当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了“开放-封闭”原则。而简单工厂模式在添加新产品对象后不得不修改工厂方法,扩展性不好。工厂方法模式退化后可以演变成简单工厂模式。

“开放-封闭”通过添加代码的方式,不是通过修改代码的方式完成功能的增强。

#include <iostream>
using namespace std;

class Fruit
{
public:
    virtual void sayname() {
        cout << "fruit\n";
    }
};

class FruitFactory
{
public:
    virtual Fruit* getFruit() {
        return new Fruit();
    }
};

class Banana : public Fruit
{
public:
    virtual void sayname() {
        cout << "banana\n";
    }
};

class BananaFactory : public FruitFactory
{
public:
    virtual Fruit* getFruit() {
        return new Banana();
    }
};

class Apple : public Fruit
{
public:
    virtual void sayname() {
        cout << "apple\n";
    }
};

class AppleFactory : public FruitFactory
{
public:
    virtual Fruit* getFruit() {
        return new Apple();
    }
};

int main()
{
    FruitFactory* fruitFactory = NULL;
    Fruit* fruit = NULL;

    fruitFactory = new BananaFactory();
    fruit = fruitFactory->getFruit();
    fruit->sayname();

    delete fruitFactory;
    delete fruit;

    fruitFactory = new AppleFactory();
    fruit = fruitFactory->getFruit();
    fruit->sayname();

    delete fruitFactory;
    delete fruit;

    return 0;
}

抽象工厂模式

抽象工厂模式是所有形态的工厂模式中最为抽象和最其一般性的。抽象工厂模式可以向客户端提供一个接口,使得客户端在不必指定产品的具体类型的情况下,能够创建多个产品族的产品对象。

  • 工厂模式:要么生产香蕉、要么生产苹果、要么生产西红柿;但是不能同时生产一个产品组。
  • 抽象工厂:能同时生产一个产品族。===》抽象工厂存在原因

重要区别:

  • 工厂模式只能生产一个产品。(要么香蕉、要么苹果)
  • 抽象工厂可以一下生产一个产品族(里面有很多产品组成)
#include <iostream>
using namespace std;

class Fruit
{
public:
    virtual void sayname() {
        cout << "fruit\n";
    }
};

class FruitFactory
{
public:
    virtual Fruit* getApple() {
        return new Fruit();
    }
    virtual Fruit* getBanana() {
        return new Fruit();
    }
};

// 南方Banana
class SouthBanana : public Fruit
{
public:
    virtual void sayname() {
        cout << "SouthBanana\n";
    }
};

// 南方Apple
class SouthApple : public Fruit
{
public:
    virtual void sayname() {
        cout << "SouthApple\n";
    }
};

// 北方Banana
class NorthBanana : public Fruit
{
public:
    virtual void sayname() {
        cout << "NorthBanana\n";
    }
};

// 北方Apple
class NorthApple : public Fruit
{
public:
    virtual void sayname() {
        cout << "NorthApple\n";
    }
};

class SouthFruitFactory : public FruitFactory
{
public:
    virtual Fruit* getApple() {
        return new SouthApple();
    }
    virtual Fruit* getBanana() {
        return new SouthBanana();
    }
};

class NorthFruitFactory : public FruitFactory
{
public:
    virtual Fruit* getApple() {
        return new NorthApple();
    }
    virtual Fruit* getBanana() {
        return new NorthBanana();
    }
};

int main()
{
    FruitFactory* fruitFactory = NULL;
    Fruit* fruit = NULL;

    fruitFactory = new SouthFruitFactory();
    fruit = fruitFactory->getApple();
    fruit->sayname();

    delete fruit;

    fruit = fruitFactory->getBanana();
    fruit->sayname();
    delete fruit;

    return 0;
}

建造者模式

  • Builder:为创建产品各个部分,统一抽象接口。
  • ConcreteBuilder:具体的创建产品的各个部分,部分A, 部分B,部分C。
  • Director:构造一个使用Builder接口的对象。
  • Product:表示被构造的复杂对象。

ConcreteBuilder创建该产品的内部表示并定义它的装配过程,包含定义组成部件的类,包括将这些部件装配成最终产品的接口。

适用情况: 一个对象的构建比较复杂,将一个对象的构建和对象的表示进行分离。

Builder模式:
1、引擎工厂生产引擎产品,得到汽车部件A。
2、轮胎工厂生产轮子产品,得到汽车部件B。
3、底盘工厂生产车身产品,得到汽车部件C。
4、将这些部件放到一起,形成刚好能够组装成一辆汽车的整体。
5、将这个整体送到汽车组装工厂,得到一个汽车产品。

这样做,目的是为了实现复杂对象生产线和其部件的解耦。强调的是过程。
#include <iostream>
#include <string>

class House
{
public:
    void SetFloor(const std::string& floor) {
        floor_ = floor;
    }

    void SetWall(const std::string& wall) {
        wall_ = wall;
    }

    void SetDoor(const std::string& door) {
        door_ = door;
    }

    const std::string& GetFloor() {
        return floor_;
    }

    const std::string& GetWall() {
        return wall_;
    }

    const std::string& GetDoor() {
        return door_;
    }

private:
    std::string floor_;
    std::string wall_;
    std::string door_;
};


class Builder
{
public:
    virtual void MakeFloor() = 0;
    virtual void MakeWall() = 0;
    virtual void MakeDoor() = 0;
    virtual House* GetHouse() = 0;
};

// 公寓
class FlatBuilder : public Builder
{
public:
    FlatBuilder() {
        house_ = new House;
    }

    virtual void MakeFloor() {
        house_->SetFloor("flat floor");
    }
    virtual void MakeWall() {
        house_->SetWall("flat wall");
    }
    virtual void MakeDoor() {
        house_->SetDoor("flat door");
    }
    virtual House* GetHouse() {
        return house_;
    }

private:
    House* house_;
};

class Director
{
public:
    void Construct(Builder* builder) {
        builder->MakeFloor();
        builder->MakeWall();
        builder->MakeDoor();
    }
};


int main()
{
    // 客户直接造房子
    {
        House* house = new House;
        house->SetFloor("floor");
        house->SetWall("wall");
        house->SetDoor("door");
        delete house;
    }
    
    // 工程队直接造房子
    {
        Builder* builder = new FlatBuilder;
        builder->MakeFloor();
        builder->MakeWall();
        builder->MakeDoor();
        House* house = builder->GetHouse();
        delete house;
        delete builder;
    }

    // 设计师指挥工程队造房子
    {
        Director* director = new Director;
        Builder* builder = new FlatBuilder;
        director->Construct(builder);  // 设计师指挥工程队
        House* house = builder->GetHouse();
        delete house;
        delete builder;
        delete director;
    }

    return 0;
}

代理模式

Proxy模式又叫做代理模式,是构造型的设计模式之一,它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。

  • subject(抽象主题角色):真实主题与代理主题的共同接口。
  • RealSubject(真实主题角色):定义了代理角色所代表的真实对象。
  • Proxy(代理主题角色):含有对真实主题角色的引用,代理角色通常在将客户端调用传递给真是主题对象之前或者之后执行某些操作,而不是单纯返回真实的对象。

适合于: 为其他对象提供一种代理以控制对这个对象的访问。 提示:a中包含b类;a、b类实现协议类protocol

// 理论模型
// 提示:a中包含b类;a、b类实现协议类protocol

#include <string>
#include <iostream>
using namespace std;
//定义接口
class Interface
{
public:
	virtual void Request()=0;
};
//真实类
class RealClass : public Interface
{
public:
	virtual void Request()
	{
		cout<<"真实的请求"<<endl;
	}
};
//代理类
class ProxyClass : public Interface
{
private:
	RealClass* m_realClass;
public:
	virtual void Request()
	{
	    m_realClass= new RealClass();
		m_realClass->Request();
		delete m_realClass;
	}
};

//客户端:
int main()
{
	ProxyClass* test=new ProxyClass();
	test->Request();
	return 0;
}
//a包含了一个类b,类b实现了某一个协议(一套接口)
class AppProtocol
{
public:
	virtual int ApplicationDidFinsh() = 0;
protected:
private:
};

//协议实现类
class AppDelegate : public AppProtocol
{
public:
	AppDelegate()
	{
		;
	}
	virtual int ApplicationDidFinsh()  //cocos2dx函数的入口点
	{
		cout<<"ApplicationDidFinsh do...\n";
		return 0;
	}
};

//Application是代理类,在代理类中包含一个真正的实体类
class Application
{
public:
	Application()
	{
		ap = NULL;
	}
public:
	void run()
	{
		ap = new AppDelegate();
		ap->ApplicationDidFinsh();
		delete ap;
	}
protected:
private:
	AppDelegate *ap;
};

//好处:main函数不需要修改了。只需要修改协议实现类
void main31()
{
	Application *app = new Application();
	app->run();

	if (app == NULL)
	{
		free(app);
	}

	cout<<"hello..."<<endl;
	system("pause");
}
class Subject
{
public:
	virtual void SaleBook() = 0;
protected:
private:
};

class RealSubject : public Subject
{
public:
	virtual void SaleBook()
	{
		cout << "实体店买书....\n";
	}
protected:
private:
};

class ProxyTaoBao : public Subject
{
public:
	virtual void SaleBook()
	{
		//
		Double11();
		RealSubject rs;
		rs.SaleBook();
		Double11();
	}
	void Double11()
	{
		cout << "Double11 打折半价" << endl;
	}
protected:
private:
};


class ProxyTaoBao2 : public Subject
{
public:
	void SetRealSubject(RealSubject *rs)
	{
		m_s = rs;
	}
	virtual void SaleBook()
	{
		Double11();
		m_s->SaleBook();
	}
	void Double11()
	{
		cout << "Double11 打折半价" << endl;
	}
protected:
private:
	RealSubject *m_s;
};

void main61()
{
	ProxyTaoBao *ptb = new ProxyTaoBao;
	ptb->SaleBook();
	delete ptb;
	return;
}

装饰模式

装饰(Decorator )模式又叫做包装模式。通过一种对客户端透明的方式来扩展对象的功能,是继承关系的一个替换方案。

装饰模式就是把要添加的附加功能分别放在单独的类中,并让这个类包含它要装饰的对象,当需要执行时,客户端就可以有选择地、按顺序地使用装饰功能包装对象。

装饰者模式(Decorator Pattern)动态的给一个对象添加一些额外的职责。就增加功能来说,此模式比生成子类更为灵活。

#include <iostream>
using namespace std;

class Car
{
public:
	virtual void show() = 0;
protected:
private:
};

class RunCar : public Car
{
public:
	void run()
	{
		cout << "可以跑" << endl;
	}
	virtual void show()
	{
		run();
	}
protected:
private:
};

class SwimCarDirector : public Car
{
public:
	SwimCarDirector(Car *p)
	{
		m_p = p;
	}

	void swim()
	{
		cout << "可以游" << endl;
	}

	virtual void show()
	{
		m_p->show();
		swim();
	}
private:
	Car *m_p;
};

class FlyCarDirector : public Car
{
public:
	FlyCarDirector(Car *p)
	{
		m_p = p;
	}

	void fly()
	{
		cout << "可以飞" << endl;
	}
	virtual void show()
	{
		m_p->show();
		fly();
	}
private:
	Car *m_p;
};

void main()
{
	Car *runcar = NULL;
	runcar = new RunCar;
	runcar->show();

	cout <<"车开始装饰swim"<<endl;
	SwimCarDirector *swimCar = new SwimCarDirector(runcar);
	swimCar->show();

	cout <<"车开始装饰fly"<<endl;
	FlyCarDirector *flyCar = new FlyCarDirector(swimCar);
	flyCar->show();

	delete flyCar;
	delete swimCar;
	delete runcar;
	
	return ;
}

享元模式

Flyweight模式也叫享元模式,是构造型模式之一,它通过与其他类似对象共享数据来减小内存占用。

例如:在文档编辑器的设计过程中,一个字母’a’在文档中出现了99999次,而实际上我们可以让它们共享一个对象,当然因为不同位置可能字母有不同的显示效果(字体,大小等),在这种情况我们可以将对象的状态分为“外部状态”和“内部状态”,将可以被共享(不会变化)的状态作为内部状态存储在对象中,而外部对象(例如上面提到的字体/大小等)可以在适当的时候将外部对象作为参数传递给对象(例如:在显示的时候,将字体/大小等信息传递给对象)。

  • 抽象享元角色:所有具体享元类的父类,规定一些需要实现的公共接口。
  • 具体享元角色:抽象享元角色的具体实现类,并实现了抽象享元角色规定的方法。
  • 享元工厂角色:负责创建和管理享元角色。

  • 使用场景:是以共享的方式,高效的支持大量的细粒度的对象。
#include <iostream>
#include <string>
#include <map>

class Person
{
public:
    Person(const std::string& name, int age) {
        name_ = name;
        age_ = age;
    }

    const std::string& GetName() { return name_; }
    int GetAge() { return age_; }

protected:
    std::string name_;
    int age_;
};

class Teacher : public Person
{
public:
    Teacher(const std::string& id, const std::string& name, int age) : Person(name, age) {
        id_ = id;
    }

    const std::string& GetId() { return id_; }

    void Show() {
        std::cout << "id: " << id_ << ", name: " << name_ << ", age: " << age_ << std::endl;
    }

private:
    std::string id_;
};

class TeacherFactory
{
public:
    TeacherFactory() {}
    ~TeacherFactory() {
        while (!pool_.empty()) {
            Teacher* t = NULL;
            auto it = pool_.begin();
            t = it->second;
            pool_.erase(it);
            delete t;
        }
    }

    Teacher* GetTeacher(const std::string& id) {
        std::string name("");
        int age = 0;
        Teacher* t = NULL;
        auto it  = pool_.find(id);
        if (it == pool_.end()) {
            std::cout << "不存在该id, 请输入以下信息进行创建!" << std::endl;
            std::cout << "name: ";
            std::cin >> name;
            std::cout << "age: ";
            std::cin >> age;
            t = new Teacher(id, name, age);
            pool_.insert(std::make_pair(id, t));
        } else {
            t = it->second;
        }
        return t;
    }

private:
    std::map<std::string, Teacher*> pool_;
};

int main()
{
    TeacherFactory* teacherFactory = new TeacherFactory;
    Teacher* t = teacherFactory->GetTeacher("001");
    t->Show();
    delete teacherFactory;
    return 0;
}

命令模式

Command模式也叫命令模式 ,是行为设计模式的一种。Command模式通过被称为 Command的类封装了对目标对象的调用行为以及调用参数。

在面向对象的程序设计中,一个对象调用另一个对象,一般情况下的调用过程是:创建目标对象实例;设置调用参数;调用目标对象的方法。 但在有些情况下有必要使用一个专门的类对这种调用过程加以封装,我们把这种专门的类称作command类。 整个调用过程比较繁杂,或者存在多处这种调用。这时,使用Command类对该调用加以封装,便于功能的再利用。- 调用前后需要对调用参数进行某些处理。调用前后需要进行某些额外处理,比如日志,缓存,记录历史操作等。

  • Command:Command命令的抽象类。
  • ConcreteCommand:Command的具体实现类。
  • Receiver:需要被调用的目标对象。
  • Invorker:通过Invorker执行Command对象。

适用于:将一个请求封装为一个对象,从而使你可用不同的请求对客户端进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。

#include <iostream>
#include <list>
using namespace std;

class Vendor
{
public:
    void SailApple() {
        std::cout << "sail apple" << std::endl;
    }
    void SailBanana() {
        std::cout << "sail banana" << std::endl;
    }
};

class Command
{
public:
    virtual void Sail() = 0;
};

class AppleCommand : public Command
{
public:
    AppleCommand(Vendor* v) {
        vendor_ = v;
    }

    Vendor* GetVendor() { return vendor_; }

    void SetVendor(Vendor* v) {
        vendor_ = v;
    }

    virtual void Sail() {
        vendor_->SailApple();
    }

private:
    Vendor* vendor_;
};


class Waiter
{
public:
    Command* GetCommand() {
        return command_;
    }

    void SetCommand(Command* c) {
        command_ = c;
    } 

    void Sail() {
        command_->Sail();
    }

private:
    Command* command_;
};

class AdvWaiter
{
public:
    AdvWaiter() {}
    ~AdvWaiter() {}

    void AddCommand(Command* c) {
        commandList_.push_back(c);
    }

    std::list<Command*>& GetCommandList() {
        return commandList_;
    }

    void Sail() {
        for (auto it = commandList_.begin(); it != commandList_.end(); ++it) {
            (*it)->Sail();
        }
    }

private:
    std::list<Command*> commandList_;
};

int main()
{
    // 小商贩 直接 卖 水果
    {
        Vendor* v = new Vendor;
        v->SailApple();
        delete v;
    }

    // 小商贩 通过命令 卖 水果
    {
        Vendor* v = new Vendor;
        AppleCommand* ac = new AppleCommand(v);
        ac->Sail();
        delete ac;
        delete v;
    }

    // 小商贩 通过waiter 卖 水果
    {
        Vendor* v = new Vendor;
        AppleCommand* ac = new AppleCommand(v);
        Waiter* w = new Waiter;
        w->SetCommand(ac);
        w->Sail();
        delete w;
        delete ac;
        delete v;
    }

    // 小商贩 通过advwaiter 批量下单 卖水果
    {
        Vendor* v = new Vendor;
        AppleCommand* ac = new AppleCommand(v);
        AdvWaiter* w = new AdvWaiter;
        w->AddCommand(ac);
        w->Sail();
        delete w;
        delete ac;
        delete v;
    }
    return 0;
}

策略模式

Strategy模式也叫策略模式是行为模式之一,它对一系列的算法加以封装,为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,具体的算法选择交由客户端决定(策略)。

Strategy模式主要用来平滑地处理算法的切换 。

策略模式优缺点

它的优点有:

  • 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
  • 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
  • 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。

策略模式的缺点有:

  • 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
  • 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
//Symmetric encryption
class Strategy
{
public:
	virtual void SymEncrypt() = 0;
};

class Des : public Strategy
{
public:
	virtual void SymEncrypt()
	{
		cout << "Des 加密" << endl; 
	}
};

class AES : public Strategy
{
public:
	virtual void SymEncrypt()
	{
		cout << "AES 加密" << endl; 
	}
};


class Context
{
public:
	Context(Strategy *strategy)
	{
		p = strategy;
	}
	void Operator()
	{
		p->SymEncrypt();
	}
private:
	Strategy *p;
};


//算法的实现 和 客户端的使用 解耦合
//使得算法变化,不会影响客户端
void main()
{
	Strategy *strategy = NULL;
	Context *ctx = NULL;

	strategy = new AES;
	ctx = new Context(strategy);
	ctx->Operator();
	delete strategy;
	delete ctx;
	return;
}

观察者模式

Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时,能够自动通知其他关联对象,自动刷新对象状态。 Observer模式提供给关联对象一种同步通信的手段,使某个对象与依赖它的其他对象之间保持状态同步。

  • Subject(被观察者):被观察的对象。当需要被观察的状态发生变化时,需要通知队列中所有观察者对象。Subject需要维持(添加,删除,通知)一个观察者对象的队列列表。
  • ConcreteSubject:被观察者的具体实现。包含一些基本的属性状态及其他操作。
  • Observer(观察者):接口或抽象类。当Subject的状态发生变化时,Observer对象将通过一个callback函数得到通知。
  • ConcreteObserver:观察者的具体实现。得到通知后将完成一些具体的业务逻辑处理。

使用场景:定义了一种一对多的关系,让多个观察对象(公司员工)同时监听一个主题对象(秘书),主题对象状态发生变化时,会通知所有的观察者,使它们能够更新自己。

#include <iostream>
using namespace std;
#include "vector"
#include "string"

class Secretary;

//玩游戏的同事类(观察者)
class PlayserObserver
{
public:
	PlayserObserver(string name, Secretary *secretary)
	{
		m_name = name;
		m_secretary = secretary;
	}
	void update(string action)
	{
		cout << "观察者收到action:" << action << endl;
	}
private:
	string		m_name;
	Secretary	*m_secretary;
};

//秘书类(主题对象,通知者)
class Secretary
{
public:
	void addObserver(PlayserObserver *o)
	{
		v.push_back(o);
	}
	void Notify(string action)
	{
		for (vector<PlayserObserver *>::iterator it= v.begin(); it!=v.end(); it++ )
		{
			(*it)->update(action);
		}
	}
	void setAction(string action)
	{
		m_action = action;
		Notify(m_action);
	}
private:
	string m_action;
	vector<PlayserObserver *> v;
};

void main()
{
	//subject 被观察者
	Secretary *s1 = new Secretary;

	//具体的观察者 被通知对象
	PlayserObserver *po1 = new PlayserObserver("小张", s1);
	//PlayserObserver *po2 = new PlayserObserver("小李", s1);
	s1->addObserver(po1);
	//s1->addObserver(po2);
	s1->setAction("老板来了");
	s1->setAction("老板走了");
	cout<<"hello..."<<endl;
	system("pause");
	return ;
}

上一篇 python学习笔记

下一篇 git and svn

Comments

Content