基于原则设计

基于原则设计（Policy-Based Class Design）又名policy-based class design 或 policy-based programming, 是一种基于C++计算机程序设计规范，以原则（Policy）为基础，并结合C++的模板超编程（template metaprogramming）。policy-based首见于 Andrei Alexandrescu 出版的 《Modern C++ Design》一书以及他在C/C++ Users Journal杂志专栏 Generic。

## 概览

Policy的意思是方针，或策略，也就是将原本复杂的系统，拆解成多个独立运作的“策略类别”（policy class），每一组policy class都只负责单纯如行为（behavior, method）或结构（structure）的某一方面。Templetes与多重继承（Multiple Inheritance）两项技术互补。多重继承由于继承自多组 Base Class，故缺乏型别讯息（type information），而Templetes基于型别，拥有丰富的型别讯息。多重继承容易扩张，而Templetes的特化（Specialization）不容易扩张。Policy-Based Class Design 同时使用了 Template 以及 Multiple Inheritance 两项技术，结合两者的优点。

```
template
<
         class Policy1,
         class Policy2,
         class Policy3
>
class PolicyBasedClass:public Policy1, public Policy2
{
public:
   PolicyBasedClass(){};
};
```

PolicyBasedClass则称为宿主类别（host class），只需要切换不同 Policy Class，就可以得到不同的需求。Policy不一定要被宿主（host）继承，只需要用委托（delegation）完成这一工作。但policies必须遵守一个隐含的constraint，界面（interface）必须一样，故参数不能有巨大改变。

Policy class有点类似回呼函式（callbacks），但不同的是，callback只是一个函式，至于 policy class 则尽可能包含许多的 functions (methods), 有时还会结合状态变数（state variables）与其他各式各样的型别，如巢状型别（nested types）。

policy 的一个重要的特征是，宿主类别（host class）经常（并不一定要）使用多重继承的机制去使用多个 policy classes. 因此在进行 policy 拆解时，必须要尽可能达成正交分解（Orthogonal Decomposition），policy彼此独立运作，不相互影响。

## Template Template Parameter

在 C++ 的Policy-Based Design 中，用来建构 Template 的类别参数（也就是policy class），本身亦可以是一个 Tempate 化的类别，形成所谓的 Template Template Parameter。

如果 Read、Write 有各种不同名目的参数时，可以利用 template 的不完全具现化 (Incomplement Instantiation) 特征检实现各个参数不同的成员函式（member function）。在host class中，可以撰写不同参数版本的 Read(...) 函式，这有赖于c++ compiler的协助。

```
template
<
	class T,
	template< class > class ReadPolicy,
	template< class > class WritePolicy
>
class ResourceManager
	:
	public ReadingPolicy< T >,
	public WritingPolicy< T >
{
public:
   void Read();
   void Write(XmlElement*);
   void Write(DataSource*);
};
```

上述的class T即是一个Template Template Parameter，这使得 Policy Class 更具扩充性与弹性，能够处理各种类型的实体（instance）。

```
void main()
{
  ResourceManager< AnimationEntity, BinaryReader, BinaryWriter > ResMgr1;
  ResourceManager< ScriptEntity, TextReader, TextWriter > ResMgr2;
}
```

## 范例

下例是 C++ hello world的范例，可以使用各种原则（policies）打印文字。

```cpp
template<
    typename output_policy,
    typename language_policy
>
class HelloWorld
  : public output_policy,
    public language_policy
{
    using output_policy::Print;
    using language_policy::Message;

public:

    //behaviour method
    void Run()
    {
        //two policy methods
        Print( Message() );
    }

};

#include <iostream>

class HelloWorld_OutputPolicy_WriteToCout
{
protected:

    template< typename message_type >
    void Print( message_type message )
    {
        std::cout << message << std::endl;
    }

};

#include <string>

class HelloWorld_LanguagePolicy_English
{
protected:

    std::string Message()
    {
        return "Hello, World!";
    }

};

class HelloWorld_LanguagePolicy_German{
protected:

    std::string Message()
    {
        return "Hallo Welt!";
    }

};

int main()
{

/* example 1 */

    typedef
        HelloWorld<
            HelloWorld_OutputPolicy_WriteToCout,
            HelloWorld_LanguagePolicy_English
        >
            my_hello_world_type;

    my_hello_world_type hello_world;
    hello_world.Run(); //returns Hello World!

/* example 2 
 * does the same but uses another policy, the language has changed
 */

    typedef
        HelloWorld<
            HelloWorld_OutputPolicy_WriteToCout,
            HelloWorld_LanguagePolicy_German
        >
            my_other_hello_world_type;

    my_other_hello_world_type hello_world2;
    hello_world2.Run(); //returns Hallo Welt!
}
```

你可以更容易的撰写其他的 Output policy, 单靠你创造更新的Policy class并实作print于其中。

## 外部链接

- Andrei Alexandrescu's Web site