设计模式——行为型模式(二)
6. Iterator——对象行为型模式
作用:
提供一种方法顺序访问一个聚合对象中的各个元素,而又不需要暴露该对象的内部表示
UML结构图:
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 | typedef int DATA; class Iterator; //容器的抽象基类 class Aggregate { public : virtual ~Aggregate(){} virtual Iterator* CreateIterator(Aggregate* pAggregate)=0; virtual int GetSize()=0; virtual DATA GetItem( int nIndex)=0; }; //迭代器的抽象基类 class Iterator { public : virtual ~Iterator(){} virtual void First()=0; virtual void Next()=0; virtual bool IsDone()=0; virtual DATA CurrentItem()=0; }; // 一个具体的容器类,这里是用数组表示 class ConcreteAggregate: public Aggregate { public : ConcreteAggregate( int nSize):m_nSize(nSize),m_pData(NULL) { m_pData = new DATA[m_nSize]; for ( int i=0;i<nSize;++i) m_pData[i] = i; } virtual ~ConcreteAggregate() { delete [] m_pData; m_pData = NULL; } virtual Iterator* CreateIterator(Aggregate* pAggregate); virtual int GetSize() { return m_nSize; } virtual DATA GetItem( int nIndex) { if (nIndex<m_nSize) return m_pData[nIndex]; else return -1; } private : int m_nSize; DATA *m_pData; }; //访问ConcreteAggregate容器类的迭代器类 class ConcreteIterator: public Iterator { public : ConcreteIterator(Aggregate* pAggregate) :m_pConcreteAggregate(pAggregate),m_nIndex(0){} virtual ~ConcreteIterator() { m_nIndex = 0; } virtual void First() { m_nIndex = 0; } virtual void Next() { if (m_nIndex<m_pConcreteAggregate->GetSize()) ++m_nIndex; } virtual bool IsDone() { return m_nIndex == m_pConcreteAggregate->GetSize(); } virtual DATA CurrentItem() { return m_pConcreteAggregate->GetItem(m_nIndex); } private : Aggregate *m_pConcreteAggregate; int m_nIndex; }; Iterator* ConcreteAggregate::CreateIterator(Aggregate* pAggregate) { return new ConcreteIterator( this ); } int main() { Aggregate* pAggregate = new ConcreteAggregate(4); Iterator* pIterator = new ConcreteIterator(pAggregate); for (; false ==pIterator->IsDone();pIterator->Next()) cout<<pIterator->CurrentItem()<<endl; return 0; } |
7. Memento——对象行为型模式
作用:
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
UML结构图:
解析:
Memento模式中封装的是需要保存的状态,当需要恢复的时候才取出来进行恢复。原理很简单,实现的时候需要注意一个地方:窄接口和宽接口。所谓宽接口是一般意义上的接口,把对外的接口作为public成员;而窄接口与之相反,把接口作为private成员,而把需要访问的这些接口函数的类作为这个类的友元类,也就是说接口只暴露给了对这些接口感兴趣的类,而不是暴露在外部。
以下的实现采用窄接口的方法来实现:
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 | typedef string State; class Memento; class Originator { public : Originator( const State& rState):m_State(rState){} Originator(){} ~Originator(){} Memento* CreateMemento(); void SetMemento(Memento* pMemento); State GetState() { return m_State; } void SetState( const State& rState) { m_State = rState; } void RestoreState(Memento* pMemento); void PrintState() { cout<< "State = " <<m_State<<endl; } private : State m_State; }; //把Memento的接口函数都设置为私有的,而Originator是它的友元,这样保证了只有Originator 可以对其访问 class Memento { private : friend class Originator; Memento( const State& rState):m_State(rState){} void SetState( const State& rState) { m_State = rState; } State GetState() { return m_State; } State m_State; }; Memento* Originator::CreateMemento() { return new Memento(m_State); } void Originator::RestoreState(Memento* pMemento) { if (NULL!=pMemento) m_State = pMemento->GetState(); } int main() { //创建一个原发器 Originator* pOriginator = new Originator( "old state" ); pOriginator->PrintState(); //创建一个备忘录存放这个原发器的状态 Memento *pMemento = pOriginator->CreateMemento(); //更改原发器的状态 pOriginator->SetState( "new state" ); pOriginator->PrintState(); //通过备忘录把原发器的状态还原到之前的状态 pOriginator->RestoreState(pMemento); pOriginator->PrintState(); delete pOriginator; delete pMemento; return 0; } |
3. Visitor模式
作用:
表示一个作用于某对象结构中的各元素的操作,它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
UML结构图:
解析:
Visitor模式把对节点的访问封装成一个抽象基类,通过派生出不同的类生成新的访问方式。在实现的时候,在visitor抽象基类中声明了对所有不同节点进行访问的接口函数,如图中的VisitorConcreteElementA函数等,这样也就造成了Visitor模式的一个缺陷——新加入一个节点的时候都要添加Visitor中对其进行访问的接口函数,这样使得所有的Visitor及其派生类都要重新编译,也就是说Visitor模式的一个缺点就是添加新的节点十分困难。
Visitor模式使用“双重分派”的技术,要对某一个节点进行访问,首先需要产生一个Element的派生类对象,其次要传入一个Visitor类派生类对象来调用对应的Accept函数,即到底对哪种Element采用哪种Visitor访问,需要两次动态绑定才可以确定下来。
实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 | class Visitor; class Element { public : virtual ~Element(){} virtual void Accept(Visitor &rVisitor)=0; protected : Element(){} }; class ConcreteElementA: public Element { public : virtual ~ConcreteElementA(){} virtual void Accept(Visitor &rVisitor); }; class ConcreteElementB: public Element { public : virtual ~ConcreteElementB(){} virtual void Accept(Visitor &rVisitor); }; class Visitor { public : virtual ~Visitor(){} virtual void VisitConcreteElementA(ConcreteElementA* pConcreteElementA)=0; virtual void VisitConcreteElementB(ConcreteElementB* pConcreteElementB)=0; protected : Visitor(){} }; class ConcreteVisitorA: public Visitor { public : virtual ~ConcreteVisitorA(){} virtual void VisitConcreteElementA(ConcreteElementA* pConcreteElementA) { cout<< "VisitConcreteElementA by ConcreteVisitorA" <<endl; } virtual void VisitConcreteElementB(ConcreteElementB* pConcreteElementB) { cout<< "VisitConcreteElementB by ConcreteVisitorA" <<endl; } }; class ConcreteVisitorB: public Visitor { public : virtual ~ConcreteVisitorB(){} virtual void VisitConcreteElementA(ConcreteElementA* pConcreteElementA) { cout<< "VisitConcreteElementA by ConcreteVisitorB" <<endl; } virtual void VisitConcreteElementB(ConcreteElementB* pConcreteElementB) { cout<< "VisitConcreteElementB by ConcreteVisitorB" <<endl; } }; void ConcreteElementA::Accept(Visitor &rVisitor) { rVisitor.VisitConcreteElementA( this ); } void ConcreteElementB::Accept(Visitor &rVisitor) { rVisitor.VisitConcreteElementB( this ); } int main() { Visitor *pVisitorA = new ConcreteVisitorA(); Element *pElement = new ConcreteElementA(); pElement->Accept(*pVisitorA); delete pElement; delete pVisitorA; return 0; } |
【推荐】国内首个AI IDE,深度理解中文开发场景,立即下载体验Trae
【推荐】编程新体验,更懂你的AI,立即体验豆包MarsCode编程助手
【推荐】轻量又高性能的 SSH 工具 IShell:AI 加持,快人一步
· 如果单表数据量大,只能考虑分库分表吗?
· 一文彻底搞懂 MCP:AI 大模型的标准化工具箱
· 电商平台中订单未支付过期如何实现自动关单?
· 用 .NET NativeAOT 构建完全 distroless 的静态链接应用
· 为什么构造函数需要尽可能的简单
· C# 多项目打包时如何将项目引用转为包依赖
· 一款让 Everything 更加如虎添翼的 .NET 开源辅助工具!
· 如果单表数据量大,只能考虑分库分表吗?
· 在Winform开发框架支持多种数据库基础上,增加对国产数据库人大金仓的支持
· ocr识别遇到的小问题-图片的EXIF 元数据