Think in in C++[vol2]【10】设计模式

1.简化习俗

1.1 信使
  • 信使(messenger)将消息封装到一个对象中到处传递,而不是将消息的所有片段分开进行传递。没有信使,下例的translate()的代码读起来非常缺乏条理。
#include <iostream>
#include <string>
using namespace std;

class Point
{
public:
    int x, y, z;
    Point(int xi, int yi, int zi) : x(xi), y(yi), z(zi) {}
    Point(const Point& p) : x(p.x), y(p.y), z(p.z) {}

    friend ostream& operator << (ostream& os, const Point& p) {
        return os << "x=" << p.x << "y=" << p.y
                  << "z=" << p.z;
    }
};

class Vector
{
    
public:
    int magnitude, direction;
    Vector(int m, int d) : magnitude(m), direction(d) {}
    ~Vector(){}
};

class Space
{
public:
    static Point translate(Point p, Vector v) {
        p.x += v.magnitude + v.direction;
        p.y += v.magnitude + v.direction;
        p.z += v.magnitude + v.direction;    
        return p;    
    }
};

int main(int argc, char const *argv[])
{
    Point p1(1, 2, 3);
    Point p2 = Space::translate(p1, Vector(11, 47));
    cout << "p1:" << p1 << " p2:" << p2 << endl;
    return 0;
}

1.2 收集参数
  • 收集参数的工作是从传递给它的函数中获取信息。通常,当收集参数被传递给多个函数的时候使用它。
  • 容器对于收集参数特别有用,因为它已经设置为动态增加对象
#include <iostream>
#include <string>
#include <vector>

class CollectingParameter : public vector<string> {   };

class Filter
{
public:
    void f(CollectingParameter& cp) {
        cp.push_back("accumulating");
    }
    void g(CollectingParameter& cp) {
        cp.push_back("items");
    }
    void h(CollectingParameter& cp) {
        cp.push_back("as we go");
    } 
};

int main(int argc, char const *argv[])
{
    Filter filter;
    CollectingParameter cp;
    filter.f(cp);
    filter.g(cp);
    filter.h(cp);
    vector<string>::iterator it = cp.begin();
    while(it != cp.end())
        cout << *it++ << endl;
    cout << endl;
    return 0;
}
1.3 单件
  • 单件允许一个类有且仅有一个实例的方法
  • 由于Singleton::instance()返回的是同一个对象,因此对s2进行set操作就是对s进行set操作
#include <iostream>
using namespace std;

//单件允许一个类有且仅有一个实例的方法
class Singleton
{
    static Singleton s;
    int i;
    //声明所有的构造函数为私有
    Singleton(int x) : i(x) {}
    //防止编译器隐式生成任何构造函数
    Singleton& operator=(Singleton&);  //放在private,根本不会被调用
    Singleton(const Singleton&);  //放在private,根本不会被调用
public:
    //返回一个共享对象的引用
    //如果返回的是指针,用户可能会不小心删除此指针;因此返回引用安全性会更高
    static Singleton& instance() { return s; }
    int getValue() { return i; }
    void setValue(int x) { i = x; } 
};

Singleton Singleton::s(47);

int main() {
    Singleton& s = Singleton::instance();
    cout << s.getValue() << endl;
    Singleton& s2 = Singleton::instance();
    s2.setValue(9);
    //由于Singleton::instance()返回的是同一个对象,因此对s2进行set操作就是对s进行set操作
    cout << s.getValue() << endl;
}
1.4 命令:选择操作
  • 命令模式对于消除代码间的耦合——清理代码有着重要的影响。
  • 最直观的角度来看,命令模式是一个函数对象。通过将函数封装为对象,就能够以参数的形式将其传递给其他函数或者对象,告诉它们在履行请求的过程中执行特定的操作。
#include <iostream>
#include <vector>
using namespace std;

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

class Hello : public Command
{
public:
    void execute() { cout << "Hello" << endl; }
};

class World : public Command {
public:
    void execute() { cout << "World!" << endl; }
}

class IAm : public Command
{
public:
    void execute() { cout << "I am the command pattern" << endl; }
};


class Macro
{
    vector<Command*> commands;
public:
    void add(Command* c) { commands.push_back(c); }
    void run() {
        vector<Command*>::iterator it = commands.begin();
        while(it != commands.end())
            (*it++) -> execute();
    }
};

int main(int argc, char const *argv[])
{
    Macro macro;
    macro.add(new Hello);
    macro.add(new World);
    macro.add(new IAm);
    macro.run();
    return 0;
}

1.5 消除对象耦合

  • 代理(Proxy)模式和状态(State)模式都提供一个代理(Surrogate)类。代码与代理类打交道,而做实际工作的类隐藏在代理类背后。当调用代理类中的一个函数时,代理类仅转而去调用实现类中相应的函数。
  • 从结构上看,代理模式是状态模式的一个特例。但是二者的内涵(intent)不同,不可理解为二者是相同的设计模式。
  • 基本思想:代理(Surrogate)类派生自一个基类,由平行地派生自同一个基类的一个或多个类提供实际的实现。当一个代理对象被创建的时候,一个实现对象就分配给了它,代理对象就将函数调用发给实现对象。
    在这里插入图片描述
  • 从结构上来看,代理模式和状态模式的区别很简单:代理模式只有一个实现类,而状态模式有多个(一个以上)实现。(在GoF中)认为这两种设计模式的应用也不同:代理模式控制对其实现类的访问,而状态模式动态地改变其实现类。
1.5.1 代理模式:作为其他对象的前端
#include <iostream>
using namespace std;

class ProxyBase
{
public:
    virtual void f() = 0;
    virtual void g() = 0;
    virtual void h() = 0;
    ~ProxyBase(){}
};

class Implementation : public ProxyBase  
{
public:
    virtual void f() { cout << "Implementation.f()" << endl; }
    virtual void g() { cout << "Implementation.g()" << endl; }
    virtual void h() { cout << "Implementation.h()" << endl; }
};

class Proxy : public ProxyBase
{
    ProxyBase* implementation;
public:
    Proxy() { implementation = new Implementation(); }
    ~Proxy(){ delete implementation; }
    //Forward calls to the implementation
    void f1() {
        implementation->f();
    }
    void g1() {
        implementation->g();
    }
    void h1() {
        implementation->h();
    }
};

int main() {
    Proxy p;
    p.f();
    p.g();
    p.h();
}
1.5.2 状态模式:改变对象的行为
#include <iostream>
using namespace std;

class ProxyBase
{
public:
    virtual void f() = 0;
    virtual void g() = 0;
    virtual void h() = 0;
    ~ProxyBase(){}
};

class Implementation : public ProxyBase  
{
public:
    virtual void f() { cout << "Implementation.f()" << endl; }
    virtual void g() { cout << "Implementation.g()" << endl; }
    virtual void h() { cout << "Implementation.h()" << endl; }
};

class Proxy : public ProxyBase
{
    ProxyBase* implementation;
public:
    Proxy() { implementation = new Implementation(); }
    ~Proxy(){ delete implementation; }
    //Forward calls to the implementation
    void f1() {
        implementation->f();
    }
    void g1() {
        implementation->g();
    }
    void h1() {
        implementation->h();
    }
};

int main() {
    Proxy p;
    p.f();
    p.g();
    p.h();
}

1.6 模板方法模式

  • 模板方法模式的一个重要特征是它的定义在基类中并且不能改动——模板方法模式就是”坚持相同的代码“。它调用其他基类函数(这些基类函数被子类重写)以便完成其工作,但是客户程序员不必直接调用这些函数:
#include <iostream>
using namespace std;

class ApplicationFramework
{
protected:
  virtual void customize1() = 0;
  virtual void customize2() = 0;

public:
  void templateMethod() {
    for (int i = 0; i < 5; ++i)
    {
      customize1();
      customize2();
    }
  }
};

//Create a new "application":
class MyApp : public ApplicationFramework
{
protected:
  void customize1() { cout << "Hello "; }
  void customize2() { cout << "World! " << endl; }

};

int main() {
  MyApp app;
  app.templateMethod();
}
  • 驱动应用程序运行的”引擎“就是模板方法模式。在GUI应用程序中,这个”引擎“就是主要的事件环。

1.7 策略模式:运行时选择算法

  • ”策略“的意思是:可以使用多种方法来解决某个问题。
#include <iostream>
using namespace std;

class NameStrategy
{
public:
	virtual void greet() = 0;
};

class SayHi : public NameStrategy
{
public:
	void greet() {
		cout << "Hi!How's it going?" << endl;
	}
};

class Ignore : public NameStrategy
{
public:
	void greet() {
		cout << "(Pretend I don't see you)" << endl;
	}
};

class Admission : public NameStrategy
{
public:
	void greet() {
		cout << "I am sorry. I forger your name." << endl;
	}
};

//The Context controls the strategy:
class Context
{
	NameStrategy& strategy;
public:
	Context(NameStrategy& strat) : strategy(strat) { }
	void greet() { strategy.greet(); }
};

int main(){
	SayHi sayhi;
	Ignore ignore;
	Admission admission;
	Context c1(sayhi), c2(ignore), c3(admission);
	c1.greet();
	c2.greet();
	c3.greet();

}

1.8 工厂模式:封装对象的创建

  • 当发现需要添加新的类型到一个系统中时,最明智的首要步骤就是用多态机制为这些新类创建一个共同的接口。
  • 用一个通用的工厂(factory)来创建对象,而不允许将创建对象的代码散布于整个系统。如果程序中所有需要创建对象的代码都转到这个工厂执行,那么在增加新对象时所要做的全部工作就是只需修改工厂。
Shape* Shape::factory(const string& type) throw(Shape::BadShapeCreation) {
		if(type == "Circle") return new Circle;
		if (type == "Square") return new Square;
		throw BadShapeCreation(type);
}
string sl[] = {"Circle", "Square", "Square","Circle", "Circle", "Circle", "Square"};
  • 在添加新的Shape类型时,函数factory()是当前系统中惟一需要修改的代码。
shapes.push_back(Shape::factory(sl[i]));
#include <iostream>
#include <stdexcept>
#include <cstddef>
#include <vector>
using namespace std;

# 为了确保对象的创建只能发生在函数factory()中,Shape的特定类型的构造函数被设为私有,同时Shape被声明为友元类,因此factory()能够访问这些构造函数。
class Shape
{
public:
	virtual void draw() = 0;
	virtual void erase() = 0;
	virtual ~Shape(){}
	class BadShapeCreation : public logic_error {
	public:
		BadShapeCreation(string type) : logic_error("Cannot create type " + type) { }
	};
	static Shape* factory(const string& type) throw(BadShapeCreation);
};

class Circle : public Shape
{
	Circle() {}
	friend class Shape;
public:
	void draw() { cout << "Circle::draw" << endl; }
	void erase() { cout << "Circle::erase" << endl; }
	~Circle() { cout << "Circle::~Circle" << endl; }
};

class Square : public Shape
{
	Square() {}
	friend class Shape;
public:
	void draw() { cout << "Square::draw" << endl; }
	void erase() { cout << "Square::erase" << endl; }
	~Square() { cout << "Square::~Square" << endl; }
};

Shape* Shape::factory(const string& type) throw(Shape::BadShapeCreation) {
		if(type == "Circle") return new Circle;
		if (type == "Square") return new Square;
		throw BadShapeCreation(type);
}

string sl[] = {"Circle", "Square", "Square","Circle", "Circle", "Circle", "Square"};

int main(int argc, char const *argv[])
{
	vector<Shape*> shapes;
	try {
		for (int i = 0; i < sizeof sl / sizeof sl[0]; ++i)
			shapes.push_back(Shape::factory(sl[i]));
	} catch (Shape::BadShapeCreation e) {
		cout << e.what() << endl;
		return EXIT_FAILURE;
	}
	for(int i = 0; i < shapes.size(); i++) {
		shapes[i] -> draw();
		shapes[i] -> erase(); 
	}
	return 0;
}

1.9 抽象工厂

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

class Obstacle
{
public:
    virtual void action = 0;
};

class Player
{
public:
    virtual void Interactwith(Obstacle*) = 0;
};

class Kitty : public Player
{
public:
    virtual virtual Interactwith(Obstacle* ob) {
        cout << "Kitty has encounted a " << endl;
        ob->action;
    }
};

class KungfuGuy : public Player
{
public:
     virtual void Interactwith(Obstacle* ob) {
        cout << "KungfuGuy now battles against a " << endl;
        ob->action;
    }
};

class Puzzle : public Obstacle
{
public:
     void action() {
        cout <<"Puzzle!!!" << endl;
    }
};

class NastyWeapon : public Obstacle
{
public:
     void action() {
        cout <<"NastyWeapon!!!" << endl;
    }
};

//The abstract factory
class GameElementFactory
{
public:
    virtual Player* makePlayer() = 0;
    virtual Obstacle* makeObstacle() = 0;
};

//Concrete factories
class KittiesAndPuzzles : public GameElementFactory
{
public:
    virtual Player* makePlayer() {
        return new NastyWeapon;
    }
};

class KillAndDismember : public GameElementFactory
{
public:
    virtual Player* makePlayer() { return new KungfuGuy; }
    virtual Obstacle* makeObstacle() {
        return new NastyWeapon;
    }
};

class GameEnvironment
{
    GameElementFactory* gef;
    Player* p;
    Obstacle* ob;
public:
    GameEnvironment(GameElementFactory* factory) : gef(factory), p(factory->makePlayer()), ob(factory->makeObstacle()) {}
    void play() { p->Interactwith(ob); }
    ~GameEnvironment{
        delete p;
        delete ob;
        delete gef;
    }
};

int main(int argc, char const *argv[])
{
    GameEnvironment g1(new KittiesAndPuzzles), g2(new KillAndDismember)
    g1.play();
    g2.play();
    return 0;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
Bruce Eckel 《Thinking in Java》(Java编程思想)作者。Eckel有20年专业编程经验,并自1986年起教育人们如何撰写面向对象程序,足迹遍及全球,成为一位知名的 C++教师和顾问,如今兼涉Java。他是C++标准委员会拥有表决权的成员之一,曾经写过另五本面向对象编程书籍,发表过150篇以上的文章,是多本计算机杂志的专栏作家。Eckel开创Software Development Conference的C++、Java、Python等多项研讨活动。拥有应用物理学学士和计算机工程学硕士学位。 目录 译者序 前言 第1章 对象导言 第2章 对象的创建与使用 第3章 C++中的C 第4章 数据抽象 第5章 隐藏实现 第6章 初始化与清除 第7章 函数重载与默认参数 第8章 常量 第9章 内联函数 第10章 名字控制 第11章 引用和拷贝构造函数 第12章 运算符重载 第13章 动态对象创建 第14章 继承和组合 第15章 多态性和虚函数 第16章 模板介绍 附录A 编码风格 附录B 编程准则 附录C 推荐读物 索引 第2卷:实用编程技术 出版者的话 专家指导委员会 译者序 前言 第一部分 建立稳定的系统 第1章 异常处理 第2章 防御性编程 第二部分 标准C++库 第3章 深入理解字符串 第4章 输入输出流 第5章 深入理解模板 第6章 通用算法 第7章 通用容器 第三部分 专题 第8章 运行时类型识别 第9章 多重继承 第10设计模式 第11章 并发 附录 附录A 推荐读物 附录B 其他 索引 

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值