0

关于这个主题有相当多的信息。这更像是一个设计问题,但我会举例说明。

假设我真的想传递一个配置文件类,它决定了用户的策略。

struct ApplicationAllowedPolicy
{
public:
    bool hasAccess() { return true; }
}

struct ApplicationProhibitedPolicy
{
public:
    bool hasAccess() { return false; }
}

template<typename ApplicationPolicy>
class Profile : private ApplicationPolicy
{
    bool hasAccess() { return ApplicationPolicy::access(); }
}

int main()
{
    Profile<ApplicationAllowedPolicy> allowed;
    Profile<ApplicationProhibitedPolicy> prohibited;

    // do something with allowed & prohibited
}

以上内容都很好,但我们假设有很多政策需要阅读。5 似乎是一个现实世界的数字,尽管可能更多。然后,假设此配置文件将应用于数百个实例,其中 5 个策略差异很大。要启动,策略行为只能在运行时知道(从文件、数据库等读取)。这很快变得无法扩展,除非我完全错过了一些东西。

我想过做一个非类型模板类作为策略。

template<int N>
struct ApplicationPolicy
{
    int policy = N;
};

Profile<ApplicationPolicy<1>> allowed;
Profile<ApplicationPolicy<0>> prohibited;

我认为这确实适用于我的情况,但我想知道这是否缺少基于策略的设计的要点。我在看到这一点的优点时遇到了问题,只是让 Profile 成为一个正常的结构,并根据需要将它的数据成员设置为 true/false。

想法?

4

2 回答 2

0

当类的行为根据策略发生显着变化时,基于策略的设计非常有用。例如,假设您希望您的类在多线程和常规上下文中都使用。然后您可以将其作为线程策略实现:

class SingleThreadedPolicy { /* ... */ }; // lock() does nothing
class MultiThreadedPolicy { /* ... */ }; // lock() actually locks

template<class T, class ThreadingPolicy>
class Queue {
    ThreadingPolicy threadPol_;
    // ...
    T pop() {
       threadPol_.lock();
       // remove an element from the queue
       threadPol_.unlock();
       return element;
    }
};

现在,实现相同结果的另外两种方法是使用(多重?)继承或在对象中设置标志并编写大量ifs。如果您有多个策略(例如存储、所有权等),第一个选项很快就会失效。第二个选项会导致代码无法维护。

因此,如果您的班级需要许多正交移动部件,基于策略的设计是一个不错的选择,并且它比其他方法更具可扩展性。

但是,您的示例似乎并不需要这种方法。访问似乎是它不可或缺的一部分:如果您无论如何都要调用hasAccess()您的代码,您可以安全地将其替换为布尔变量。

于 2015-08-04T21:36:13.797 回答
0

如果您想在运行时改变行为,请使用策略模式而不是基于策略的设计。

于 2020-07-05T13:00:34.830 回答