如何使用容器中对象的继承层次结构来维护开放/封闭原则
How to maintain the open/closed principle with inheritance hierarchies of objects in containers?
当我想向这个结构添加功能而不改变它时:
class MemberBase
{
public:
virtual MemberBase* clone() const;
virtual void action1();
...
}
class Container
{
public:
virtual void functionUsingAction1();
...
private:
std::vector<MemberBase*> members_
}
我可以子类成员库和
class MemberType1 : public MemberBase
{
public:
MemberBase* clone() const;// Reimplementation
void action1(); // Reimplementation
virtual void action2(); // New functionality
}
我可以通过使用
MemberBase* MemberBase::clone() const;
方法。但是我该怎么打电话
void MemberType1::action2();
从容器类的方法?我可以使用dynamic_cast,但这被认为是设计缺陷。有什么解决方法吗?或者更好的是,我可以遵循任何模式?
老实说,我看得越多,对我来说它看起来像一个典型的访问者应用程序。
我建议避免在Container
类中实现任何智能,而是将操作委托给特定的Visitor
类。可以为基础Visitor
提供某种方式来安全地与底层容器结构进行交互(擦除/插入)。
// MemberBase.hpp
class Visitor;
class MemberBase {
public:
virtual MemberBase* clone() const = 0;
virtual void accept(Visitor&) = 0;
virtual void accept(Visitor&) const = 0;
}; // class MemberBase
// Visitor.hpp
class Member1;
class Member2;
class Visitor {
public:
virtual void visit(Member1&) = 0;
virtual void visit(Member1 const&) = 0;
virtual void visit(Member2&) = 0;
virtual void visit(Member2 const&) = 0;
};
// Container.hpp
#include <MemberBase.hpp>
class Container {
public:
void accept(Visitor& v) {
BOOST_FOREACH(MemberBase& mb, _members) {
mb.accept(v);
}
}
void accept(Visitor& v) const {
BOOST_FOREACH(MemberBase const& mb, _members) {
mb.accept(v);
}
}
private:
boost::ptr_vector<MemberBase> _members;
};
然后,您需要实现成员的accept
方法。这纯粹是机械的。
// Member1.hpp
#include <MemberBase.hpp>
class Member1: public MemberBase {
public:
virtual Member1* clone() const { return new Member1(*this); }
virtual void accept(Visitor& v);
virtual void accept(Visitor& v) const;
};
// Member1.cpp
#include <Member1.hpp>
#include <Visitor.hpp>
void Member1::accept(Visitor& v) { v.visit(*this); }
void Member1::accept(Visitor& v) const { v.visit(*this); }
最后,您可以实现一个访问者:
// CountVisitor.hpp
#include <Visitor.hpp>
class CountVisitor: public Visitor {
public:
CountVisitor(): _count(0) {}
size_t count() const { return _count; }
virtual void visit(Member1&);
virtual void visit(Member1 const&);
virtual void visit(Member2&);
virtual void visit(Member2 const&);
private:
size_t _count;
};
// CountVisitor.cpp
#include <CountVisitor.hpp>
//#include <Member1.hpp> // where you would include, but unnecessary here
void CountVisitor::visit(Member1&) { ++_count; }
void CountVisitor::visit(Member1 const&) { ++_count; }
void CountVisitor::visit(Member2&) { ++_count; }
void CountVisitor::visit(Member2 const&) { ++_count; }
您可以将其用作:
// main.cpp
#include <iostream>
#include <Container.hpp>
#include <CountVisitor.hpp>
int main() {
Container const c = /* something */;
CountVisitor cv;
c.accept(cv);
std::cout << cv.count() << " items in the containern";
}
这种设计的缺点是需要为每个直接从MemberBase
派生的新类实现一个新的visit
方法,因此MemberBase
层次结构不是那么开放。这可以使用非循环访客来缓解;但是,我很少需要它。
为了"扩展"能力,你可以让Visitor::visit
并MemberBase::accept
返回要执行的"操作"(擦除、克隆等),并在你实际拥有的两个循环中处理这个问题。可以使用一些技巧将其减少到一个循环...
如果你知道每个成员会发布不同的函数,你可以总是创建像EnumerateActions(),CallAction(std::string action)等方法——这会更安全,但可以比作用火箭筒射击麻雀。
另一种选择是创建接口:IAction1,IAction2并在成员派生类中实现它们。然后,您只需检查成员是否实现接口并使用它。容器不会识别特定的成员类,但您仍然可以访问其特定功能。
我能想到的一个选项 o 检查每个对象是否是 MemberType1 对象,如果条件为真,那么您可以调用 action2()。这是一个非常幼稚的解决方案,但我相信其他人很快就会想出一个聪明的解决方案:)
- 如何维护资源管理器项目视图中当前可见的项目列表
- 维护unordered_map但同时每一步都需要最低的映射值
- С++ wxWidgets:代码架构,设计原则和模式
- GCC,CMake,预编译标头和维护依赖项
- Q没有管理权限的 exe 无法启动维护工具
- 我需要如何更改我的程序以使用打开/关闭原则?
- 是否很好地使用状态模式来维护当前选定的对象?
- 复制赋值函数如何访问另一个对象的私有成员(Stroustroup 原则和实践书)?
- Visual Studio 2017扩展选项卡中的C++核心指导原则检查器丢失
- 是否有一种设计模式或面向对象的基本原则来处理这种共享资源的情况?
- 如何维护对 std::p riority_queue 容器的引用?
- 维护/维持两个代码集的风险,一个用于 CPU,一个用于 GPU,需要执行非常相似的功能
- 分层状态机涉及哪些原则,以及如何实现基本模型?
- 如何应用注册表模式使"select class depend on input"遵守开放封闭原则?
- 将Qt应用程序维护为模块和库
- 树不维护递归迭代器成员
- 不兼容的操作原则到三元op
- 为多个类实例维护共享_ptr的静态列表
- 如何维护V8上下文以备将来使用
- 如何使用容器中对象的继承层次结构来维护开放/封闭原则