基于策略的设计 - 有条件地使用 Base class(函数)
Policy Based Design - Conditional use of Base class (functions)
在来自 wikipedia 的基于策略的设计的 hello world 示例中,我们有通过 using
指令定义实现(策略)特定成员函数的非常好的方法:
template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using LanguagePolicy::Message;
using OutputPolicy::Print;
};
现在假设您想让用户忘记在语言策略中实施 Message
方法 - 用户可能实施了很多其他方法。因此,您定义了后备 class
class DefaultLanguagePolicy {
protected:
std::string Message() const { return ""; }
// and fallbacks for other methods a user may not have implemented
}
但是,如果 Message
未在 HelloWorld
Class 中实现,您如何启用此默认值并在其他情况下丢弃它?
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy, private DefaultLanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
// what do I need to write to get this kind of behaviour:
if (LanguagePolicy has Message implemented) {
using LanguagePolicy::Message;
} else {
using DefaultLanguagePolicy::Message;
}
using OutputPolicy::Print;
};
感谢您提出的任何建议,这些建议在理想情况下可以保留这种漂亮的 using
语法。
您可以将模板参数设置为默认值,如果用户未提供第二个模板参数,class 将使用您的 DefaultLanguagePolicy。这符合您的目的吗?
`DefaultLanguagePolicy` 必须在 class `HelloWorld` 之前定义。
class DefaultLanguagePolicy {
protected:
std::string Message() const { return "Please add a language policy\n"; }
};
template <typename OutputPolicy, typename LanguagePolicy = DefaultLanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
public:
void Run() const {
Print(Message());
}
如果未提供语言政策,测试 运行 将打印“请添加语言政策”。
int main() {
typedef HelloWorld<OutputPolicyWriteToCout> myDeafult;
myDeafult forgetLanguage;
forgetLanguage.Run();
HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> InGerman;
InGerman.Run();
}
如果可以在项目中设置设计决策,则每个策略都派生自默认策略——如:
class SomeLangaugePolicy : public DefaultLanguagePolicy { ... };
然后 class 中没有任何更改 HelloWorld
- 我的意思是这个 class.
的第一个版本
否则 - 使用来自 <type_traits>
:
的工具
可以检测给定的class是否有消息功能
template <typename T, typename = std::void_t<>>
struct has_message : std::false_type {};
template <typename T>
struct has_message<T, std::void_t<decltype(&T::Message)>> : std::true_type {};
有了这个 has_message
特征,std::conditional_t
可以 select 类型取决于 Message
存在:
template <typename LanguagePolicy, typename DefaultLanguagePolicy>
using LanguageBase = std::conditional_t<has_message<LanguagePolicy>::value,
LanguagePolicy,
DefaultLanguagePolicy>;
并且需要在您的 class 中进行修改:
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld :
private OutputPolicy,
private LanguageBase<LanguagePolicy, DefaultLanguagePolicy> {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using LanguageBase<LanguagePolicy, DefaultLanguagePolicy>::Message;
using OutputPolicy::Print;
};
工作Demo
现在很容易对 OutputPolicy 和所有其他策略执行相同的操作。
您可以定义宏来定义策略检测器:
#define DEFINE_HAS_FUNCTION_TRAIT(function) \
template <typename T, typename = std::void_t<>> \
struct has_##function : std::false_type {}; \
template <typename T> \
struct has_##function<T, std::void_t<decltype(&T::function)>> : std::true_type {}
然后:
DEFINE_HAS_FUNCTION_TRAIT(Message); // define has_Message
DEFINE_HAS_FUNCTION_TRAIT(Print); // define has_Print
要处理给定策略中的功能多于一个的情况 - 使用此方法:
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld :
private OutputPolicy,
private LanguagePolicy, private DefaultLanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using std::conditional_t<has_Message<LanguagePolicy>::value,
LanguagePolicy,
DefaultLanguagePolicy>::Message;
using OutputPolicy::Print;
};
在来自 wikipedia 的基于策略的设计的 hello world 示例中,我们有通过 using
指令定义实现(策略)特定成员函数的非常好的方法:
template <typename OutputPolicy, typename LanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using LanguagePolicy::Message;
using OutputPolicy::Print;
};
现在假设您想让用户忘记在语言策略中实施 Message
方法 - 用户可能实施了很多其他方法。因此,您定义了后备 class
class DefaultLanguagePolicy {
protected:
std::string Message() const { return ""; }
// and fallbacks for other methods a user may not have implemented
}
但是,如果 Message
未在 HelloWorld
Class 中实现,您如何启用此默认值并在其他情况下丢弃它?
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy, private DefaultLanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
// what do I need to write to get this kind of behaviour:
if (LanguagePolicy has Message implemented) {
using LanguagePolicy::Message;
} else {
using DefaultLanguagePolicy::Message;
}
using OutputPolicy::Print;
};
感谢您提出的任何建议,这些建议在理想情况下可以保留这种漂亮的 using
语法。
您可以将模板参数设置为默认值,如果用户未提供第二个模板参数,class 将使用您的 DefaultLanguagePolicy。这符合您的目的吗?
`DefaultLanguagePolicy` 必须在 class `HelloWorld` 之前定义。
class DefaultLanguagePolicy {
protected:
std::string Message() const { return "Please add a language policy\n"; }
};
template <typename OutputPolicy, typename LanguagePolicy = DefaultLanguagePolicy>
class HelloWorld : private OutputPolicy, private LanguagePolicy {
public:
void Run() const {
Print(Message());
}
如果未提供语言政策,测试 运行 将打印“请添加语言政策”。
int main() {
typedef HelloWorld<OutputPolicyWriteToCout> myDeafult;
myDeafult forgetLanguage;
forgetLanguage.Run();
HelloWorld<OutputPolicyWriteToCout, LanguagePolicyGerman> InGerman;
InGerman.Run();
}
如果可以在项目中设置设计决策,则每个策略都派生自默认策略——如:
class SomeLangaugePolicy : public DefaultLanguagePolicy { ... };
然后 class 中没有任何更改 HelloWorld
- 我的意思是这个 class.
否则 - 使用来自 <type_traits>
:
template <typename T, typename = std::void_t<>>
struct has_message : std::false_type {};
template <typename T>
struct has_message<T, std::void_t<decltype(&T::Message)>> : std::true_type {};
有了这个 has_message
特征,std::conditional_t
可以 select 类型取决于 Message
存在:
template <typename LanguagePolicy, typename DefaultLanguagePolicy>
using LanguageBase = std::conditional_t<has_message<LanguagePolicy>::value,
LanguagePolicy,
DefaultLanguagePolicy>;
并且需要在您的 class 中进行修改:
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld :
private OutputPolicy,
private LanguageBase<LanguagePolicy, DefaultLanguagePolicy> {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using LanguageBase<LanguagePolicy, DefaultLanguagePolicy>::Message;
using OutputPolicy::Print;
};
工作Demo
现在很容易对 OutputPolicy 和所有其他策略执行相同的操作。
您可以定义宏来定义策略检测器:
#define DEFINE_HAS_FUNCTION_TRAIT(function) \
template <typename T, typename = std::void_t<>> \
struct has_##function : std::false_type {}; \
template <typename T> \
struct has_##function<T, std::void_t<decltype(&T::function)>> : std::true_type {}
然后:
DEFINE_HAS_FUNCTION_TRAIT(Message); // define has_Message
DEFINE_HAS_FUNCTION_TRAIT(Print); // define has_Print
要处理给定策略中的功能多于一个的情况 - 使用此方法:
template <typename OutputPolicy, typename LanguagePolicy, typename DefaultLanguagePolicy>
class HelloWorld :
private OutputPolicy,
private LanguagePolicy, private DefaultLanguagePolicy {
public:
// Behavior method.
void Run() const {
// Two policy methods.
Print(Message());
}
private:
using std::conditional_t<has_Message<LanguagePolicy>::value,
LanguagePolicy,
DefaultLanguagePolicy>::Message;
using OutputPolicy::Print;
};