基于策略的设计和最佳实践 - C++
struct InkPen
{
void Write()
{
this->WriteImplementation();
}
void WriteImplementation()
{
std::cout << "Writing using a inkpen" << std::endl;
}
};
struct BoldPen
{
void Write()
{
std::cout << "Writing using a boldpen" << std::endl;
}
};
template<class PenType>
class Writer : public PenType
{
public:
void StartWriting()
{
PenType::Write();
}
};
int main()
{
Writer<InkPen> writer;
writer.StartWriting();
Writer<BoldPen> writer1;
writer1.StartWriting();
return 0;
}
我编写上述代码是学习基于策略的设计的一部分。 我对上面的代码有几个问题
1 - 这个实现看起来正确吗? 我的意思是:它真的看起来像基于策略的设计吗?
2 - 我现在可以将任何类型的笔连接到 writer。 但是,当我得到一支没有默认构造函数(只有参数化构造函数)的笔时,我该怎么办? 我将如何处理这种情况?
template<class PenType>
class Writer : public PenType
{
public:
void StartWriting()
{
PenType::Write();
}
};
3 - 当使用上面的代码时,
Writer<InkPen> writer;
我猜编译器会将 PenType 替换为 InkPen。 如果是,为什么我无法从 StartWriting() 中调用 Write(),而不是添加基类名称前缀 (PenType::Write()) em>)?
4 - 我认为基于策略的设计迫使您从语义上无效的类中派生。 在上面的代码中,writer 是从 pen 派生出来的,只是因为 writer 使用了 pen。 但说作家是一支笔在语义上是无效的。 还有其他更好的方法来解决这个问题还是我在这里遗漏了一些东西?
有什么想法吗?
struct InkPen
{
void Write()
{
this->WriteImplementation();
}
void WriteImplementation()
{
std::cout << "Writing using a inkpen" << std::endl;
}
};
struct BoldPen
{
void Write()
{
std::cout << "Writing using a boldpen" << std::endl;
}
};
template<class PenType>
class Writer : public PenType
{
public:
void StartWriting()
{
PenType::Write();
}
};
int main()
{
Writer<InkPen> writer;
writer.StartWriting();
Writer<BoldPen> writer1;
writer1.StartWriting();
return 0;
}
I wrote the above code as part of learning policy based designs. I have few questions on the above code
1 - Does this implementation look correct? I mean: does it really look like a policy based design?
2 - I can now hook any kind of pens to writer. But what will I do when I got a pen with no default constructor (only parameterized constructors)? How will I handle this situation?
template<class PenType>
class Writer : public PenType
{
public:
void StartWriting()
{
PenType::Write();
}
};
3 - When the above code is used like
Writer<InkPen> writer;
I guess compiler will replace PenType with InkPen. If yes, why I am not able to call just Write() from StartWriting() instead of prefixing base class name (PenType::Write())?
4 - I think policy based design forces you to derive from classes which is semantically invalid. In the above code, a writer is derived from a pen only because writer uses a pen. But saying writer is a pen is semantically invalid. Is there any other better way to address this or I am missing something here?
Any thoughts?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
这看起来像是基于策略的智能指针实现的一个很好的示例:链接。 Andrei Alexandrescu 在他的一本书中描述了基于策略的智能指针实现。 至于你现在的问题。 我在这方面有一些经验,但还不足以将我的话视为理所当然:
广告 1 和广告 2。 4. 我认为基于策略的设计更多的是关于模板而不是继承。 您编写一个模板类,模板参数是策略类,如下所示:
然后您在类中使用策略类中的方法:
在本例中我使用静态方法,因为策略通常不需要任何状态。 如果是这样,您可以通过组合而不是通过继承来合并策略的状态:
Ad 2.您可以编写模板专业化 - 对于主类及其策略的特定组合,您可以编写任何方法或构造函数的特殊版本,据我所知:
希望这对你有一点帮助,
迈克
This looks like a nice example of policy-based smart pointer implementation: link. Andrei Alexandrescu describes policy-based smart pointer implementation in one of his books. As to your questions now. I have some experience in this stuff but not enough to take my words for granted:
Ad 1 & 4. I guess policy-based design is more about templates than inheritance. You write a template class and template arguments are policy classes, like that:
Then you use methods from policy classes in your class:
I use static methods in this example because often policy doesn't require any state. If it does, you incorporate policy's state by composition, not by inheritance:
Ad 2. You can write a template specialization - for a particular combination of main class and it's policies you can write a special version of any method or constructor, AFAIK:
Hope it helps you a bit,
Mike
策略类的有用性来自于组合行为以产生丰富的组合。 当您拥有像这样的单个模板参数时,它就不再是一个策略类。
这又是一个奇怪的策略类示例。 但是,要直接回答您的问题,您可以提供一个接受 PenType 的构造函数。 您可能还应该避免从 PenType 继承并将其存储为成员(无需将您的策略类与其策略紧密耦合)。
当您从类模板继承时,您必须指定 this->member 或 BaseClass::member。
按照上面的建议将 PenType 存储为成员。 总是更喜欢组合而不是继承,因为它避免了继承的紧密耦合关系。
Policy classes derive their usefulness from combining behaviors to produce a rich variety of combinations. When you have a single template parameter like this, it's not much of a policy class.
Again, this is an odd example of a policy class. However, to directly answer your question, you can provide a constructor which accepts PenType. You should probably also avoid inheriting from PenType and store it as a member instead (no need to tightly couple your policy class with its policies).
When you inherit from a class template, you have to specify this->member or BaseClass::member.
Store PenType as a member as suggested above. Always prefer composition to inheritance as it avoids the tight coupling relationship of inheritance.
我知道这个线程很旧,但是在最初的帖子中有一个重大缺陷,并且这个线程是 Google 的顶级结果之一......所以:
不要使用
public
继承进行基于策略的设计! 这会说“is-a”而不是“has-a”/“uses-a”。 因此,您应该使用private
继承!I know this thread is old, but there is a major flaw in the initial post and this thread is one of the top results of Google...so:
Do not use
public
inheritance for policy-based design! This would say "is-a" instead of "has-a" / "uses-a". You should therefore useprivate
inheritance!这是我实现该类的方式:
这允许用户将特定的 Pen 对象传递给构造函数,如果它没有默认构造函数,或者您不希望使用它,其次,它仍然允许如果您愿意让它使用默认构造函数创建一个 PenType 对象,则可以忽略它。 C++ 标准库在许多类中执行相同的操作(例如,考虑容器类的分配器)。
我删除了继承。 它似乎并没有真正添加任何东西(并且可能会导致问题。您可能不希望 Writer 类的用户直接调用 PenType::Write 函数。您可以使用私有继承来代替,但通常,组合是一个 一般来说,基于策略的设计
不需要继承,如果您确实要继承,请将其设为私有,这样您就不会遇到您提到的问题#。 4.
Here's how I would implement the class:
This allows the user to pass a specific Pen object to the constructor, if it either doesn't have a default constructor, or you don't want it to be used, and second, it still allows you to omit the PenType object if you're happy to let it create one with the default constructor. The C++ standard library does the same in many classes (think of the allocators for container classes for example).
I removed the inheritance. It didn't really seem to add anything (and might cause problems. You probably don't want the user of the Writer class to call the PenType::Write function directly. You could use private inheritance instead, but often, composition is a simpler and more conventional design.
In general, policy-based design does not require inheritance. Adding it as a member works just as well. If you do go for inheritance, make it private so you don't get the problem you mentioned as #4.