基於原則設計

基於原則設計（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