Przeglądaj źródła

添加一些设计模式

usuiforhe 4 lat temu
rodzic
commit
00f28e9aae
1 zmienionych plików z 325 dodań i 1 usunięć
  1. 325 1
      cpp/设计模式.md

+ 325 - 1
cpp/设计模式.md

@@ -1091,4 +1091,328 @@ class NetworkProcessor
 2. 为不同的状态引入不同的对象使得状态转换变得更加明确,而且可以保证不会出现状态不一致的情况,因为转换是原子性的——要么彻底转换过来,要么不转换
 3. 如果状态对象没有实力变量,那么各个上下文可以共享同一个状态对象,从而节省对象的开销
 
-### 备忘录
+### 备忘录
+
+在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态
+
+```cpp
+class Moment{	// 备忘录
+private:
+	std::string state;
+public:
+	Moment(std::string s) : state(s) {}
+	std::string getState() const { return this->state; }
+	void setState(const std::string& s) { this->state = s; }
+};
+
+class Originator {	// 原发器
+private:
+	std::string state;
+public:
+	Moment createMoment(){
+		Moment moment(state);
+		return moment;				// 记录状态
+	}
+	void setMoment(const Moment &m){
+		this->state = m.getState();	// 恢复状态
+	}
+};
+```
+
+> 这里的记录状态可能不止一个state字符串,可能存在很多其他信息,存在一些特殊的序列化技术或内存编码技术记录状态  
+
+1. 备忘录 存储 原发器(Originator)对象的内部状态,在需要时恢复原发器状态
+2. 备忘录模式的核心是信息隐藏,即原发器需要向外界隐藏信息,保持其封装性。但同时又需要将状态保持到外界的备忘录中
+3. 某些语言(C#、Java)的特性,可以很方便、跨界的通过序列化实现备忘录模式
+
+### 组合模式
+
+软件在某些情况下,客户代码过多的依赖于对象容器复杂的内部实现结构,对象容器内部实现结构(非抽象接口)的变化将引起客户代码的频繁变化,带来了代码的维护性、扩展性等弊端
+
+组合模式将对象组合成树形结构以表示**部分-整体**的层次结构,组合模式使得用户对单个对象和组合对象的使用具有一致性(稳定)
+
+```cpp
+
+/**
+ * Composite 组合设计模式
+ * 例子:需要一个文件管理系统(包括文件和文件夹)
+ * Component作为基类、Primitive作为单个文件、Composite作为文件
+ **/
+
+class Component
+{
+  private:
+  	int value;
+
+  public:
+    Component(int val) { value = val; }
+    virtual void add() {}
+};
+
+class Primitive : public Component		// 文件
+{
+  public:
+    Primitive(int val) : Component(val) {}
+};
+
+class Composite : public Component	// 文件夹
+{
+    std::vector<Component *> _c;	// 既可以存储文件也可以存储文件夹
+
+  public:
+    Composite(int val) : Component(val) {}
+    void add(Component *elem)
+    {
+        _c.push_back(elem);
+    }
+};
+```
+
+> 通过组合模式的方式,将树形结构的访问限制在了这个类的内部
+
+1. 组合模式将采用树形结构来实现普遍存在的对象模型,从而将一对多的关系转换为一对一的关系,是的客户代码可以一致地(复用)处理对象和对象容器,无需关心处理的是单个的对象,还是组合的对象容器
+2. 将客户代码与复杂的对象容器结构解耦是组合模式的核心思想,解耦之后,客户代码将与存粹的抽象接口——而非对象容器的内部实现结构——发生依赖,从而更能应对变化
+3. 组合模式再具体实现中,可以让父对象中的子对象反向追溯;如果父对象有频繁的遍历需求,可使用缓存技术改善效率
+
+### 迭代器模式
+
+在软件构建中,集合对象内部结构常常变化各异。但对于这些集合对象,我们希望在不暴露其内部结构的同时,可以让外部客户代码透明地访问其中包含的元素;同时这种**透明遍历**也为**同一种算法在多种集合对象上进行操作**提供了可能
+
+使用面向对象技术将这种遍历机制抽象为**迭代器对象**为**应对变化中的集合对象**提供了一种优雅的方式
+
+迭代器模式提供一种方法顺序访问一个聚合对象中的各个元素,而 又不暴露(稳定)该对象的内部表示
+
+
+Iterator.h
+```cpp
+template<class Item>
+
+class Iterator
+{
+public:
+    Iterator() {};
+    virtual ~Iterator() {};
+
+    virtual void first() = 0;
+    virtual void next() = 0;
+    virtual Item *curItem() = 0;
+    virtual bool isDone() = 0;
+};
+```
+ConcreteIterator.h
+```cpp
+#pragma once
+#include "Iterator.h"
+
+template<class Item>
+
+class ConcreteIterator : public Iterator <Item>
+{
+public:
+    ConcreteIterator(Aggregate<Item> *a) :aggr(a), cur(0) {};
+    virtual ~ConcreteIterator() {};
+
+    virtual void first();
+    virtual void next();
+    virtual Item *curItem();
+    virtual bool isDone();
+private:
+    Aggregate<Item> *aggr;
+    int cur;
+};
+
+template<class Item>
+void ConcreteIterator<Item>::first()
+{
+    cur = 0;
+}
+
+template<class Item>
+void ConcreteIterator<Item>::next()
+{
+    if (cur < aggr->getSize())
+        cur++;
+}
+
+template<class Item>
+Item *ConcreteIterator<Item>::curItem()
+{
+    if (cur < aggr->getSize())
+    {
+        return &(*aggr)[cur];
+    }
+    else
+    {
+        return NULL;
+    }
+}
+
+template<class Item>
+bool ConcreteIterator<Item>::isDone()
+{
+    return cur >= aggr->getSize();
+}
+```
+Aggregate.h
+```cpp
+#pragma once
+#include "Iterator.h"
+
+template<class Item>
+class Aggregate{
+public:
+    Aggregate() {};
+    virtual ~Aggregate() {};
+
+    virtual void pushData(Item item) = 0;
+    virtual Iterator<Item>* createIterator() = 0;
+    virtual Item& operator[](int index) = 0;
+    virtual int getSize() = 0;
+};
+```
+ConcreteAggregate.h
+```cpp
+#pragma once
+#include <vector>
+#include "Aggregate.h"
+#include "ConcreteIterator.h"
+
+using namespace std;
+
+template <class Item>
+class ConcreteAggregate : public Aggregate<Item>
+{
+public:
+    ConcreteAggregate() {};
+    virtual ~ConcreteAggregate() {};
+
+    virtual void pushData(Item item);
+    virtual Iterator<Item>* createIterator();
+    virtual Item& operator[](int index);
+    virtual int getSize();
+private:
+    vector<Item> data;
+};
+
+template <class Item>
+void ConcreteAggregate<Item>::pushData(Item item)
+{
+    data.push_back(item);
+}
+
+template <class Item>
+Iterator<Item>* ConcreteAggregate<Item>::createIterator()
+{
+    return new ConcreteIterator<Item>(this);
+}
+
+template <class Item>
+Item& ConcreteAggregate<Item>::operator[](int index)
+{
+    return data[index];
+}
+
+template <class Item>
+int ConcreteAggregate<Item>::getSize()
+{
+    return data.size();
+}
+```
+测试代码
+```cpp
+int main(int argc, char *argv[])
+{
+
+    Aggregate<int> * aggr = new ConcreteAggregate<int>();
+    aggr->pushData(3);
+    aggr->pushData(2);
+    aggr->pushData(1);
+    Iterator<int> * it = aggr->createIterator();
+
+    for (it->first(); !it->isDone(); it->next())
+    {
+        std::cout << *it->curItem() << std::endl;
+    }
+    delete it;
+    delete aggr;
+}
+```
+
+> 版权声明:本文为CSDN博主「MachineChen」的原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接及本声明。
+> 原文链接:https://blog.csdn.net/u012611878/article/details/78010435
+> [代码来源](https://blog.csdn.net/u012611878/article/details/78010435)
+
+1. 迭代抽象:访问一个聚合对象的内容而无需暴露它的内部表示
+2. 迭代多态:为遍历不同的集合结构提供一个统一的接口,从而支持同样的算法在不同的集合构造上进行操作
+3. 迭代器的健壮性考虑:遍历的同时更改迭代器所在的数据结构,会导致问题
+
+### 职责链模式
+
+在软件构建过程中,一个请求可能被多个对象处理,但是每个请求在运行时只能有一个接受者,如果显式指定,将必不可少地带来请求发送者与接受者的紧耦合
+
+职责链模式使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连城一条链,并沿着这条链传递请求,知道有一个对象处理它为止  
+
+```cpp
+
+class Request
+{
+    std::string description;
+    RequestType reqType;
+
+  public:
+    Request(const std::string &desc, RequestType &type) : description(desc), reqType(type) {}
+    RequestType getRequestType() { return reqType; }
+    const std::string &GetDescription() { return description; }
+};
+
+class ChainHandler
+{
+    ChainHandler *nextChain;
+    void sendRequestToNExtHandler(const Request &rqe) // 传递给链表的下一个
+    {
+        if (nextChain != nullptr)
+        {
+            nextChain->handler(rqe);
+        }
+    }
+
+  protected:
+    virtual void processRequest(const Request &req) = 0;   // 处理,如何处理交给子类处理
+    virtual bool canHandleRequest(const Request &req) = 0; // 判断是否需要处理,交给子类来判断
+
+  public:
+    ChainHandler() { nextChain = nullptr; }
+    void setNextChain(ChainHandler *next) { nextChain = next; }
+    void handle(const Request &req)
+    {
+        if (canHandleRequest(req))
+        {
+            processRequest(req);
+        }
+        else
+        {
+            sendRequestToNExtHandler(req);
+        }
+    }
+};
+class Handler_1 : public ChainHandler{};	// 第一种处理
+class Handler_2 : public ChainHandler{};	// 第二种处理
+class Handler_3 : public ChainHandler{};	// 第三种处理
+
+int main(){
+	Handler_1 h1;
+	Handler_2 h2;
+	Handler_3 h3;
+	h1.setNextChain(&h2);
+	h2.setNextChain(&h3);
+	Request req("open", RequestType::Open );
+	h1.handle(req);
+	return 0;
+}
+```
+
+1. 职责链模式的应用场合在于**一个请求可能有多个接受者,但是最后真正的接受者只有一个**,这时候请求发送者与接受者的耦合有可能出现**变化脆弱**的症状,职责链的目的就是将二者解耦,从而更好地应对变化
+2. 应用了职责链模式后,对象的职责分配将更具灵活性。可以动态添加、修改请求的处理职责  
+3. 如果请求到职责链末尾仍没有被处理,应该有一个缺省机制来处理这种请求
+
+### 命令模式