跳至內容

Trait (計算機科學)

本頁使用了標題或全文手工轉換
維基百科,自由的百科全書

Trait面向對象程序設計中,是一個不可實例化(uninstantiable)的方法與類型的集合,為一個對象或算法提供了策略(policy)或實現自身接口的細節功能。trait為類提供了一套方法,同時也意味着類必須實現這麼一套方法。

面向對象程序設計中,protocol、interface、trait、mixin具有類似的涵義。protocol/interface定義了函數原型;trait還定義了方法的完全實現;mixin除了方法的完整實現,還可以通過成員變量保存了狀態信息,而trait通常不會如此。理論上,traits支持一批組合(composition)操作:

  • 合併不相交的traits(symmetric sum)產生一個新的trait
  • 覆蓋(asymmetric sum):對一個已有的trait增加方法,可以覆蓋已有的方法
  • 別名(alias): 對已有方法增加別名,從而產生一個新的trait
  • 排除(exclusion):從已有trait中刪除方法從而產生一個新的trait
  • 嵌套的trait自動平面化。例如 給定trait S = A + X, 其中 X = B + C, 那麼trait T = A + B + C 等價於 S

C++編程中的traits

[編輯]

C++語言標準沒有定義"traits",但定義了"traits class":

17.3.25 [defns.traits] traits class

一個類,封裝了一套對類模板和函數模板實例化時操縱對象類型是必須的類型和函數 [ 注釋: 定義在Clauses 21, 22 和 27的traits class是字符traits, 提供了string和iostream類所需的字符處理支持。]

C++標準模板庫中大量使用了traits。將因為模板形參(包括類型形參、非類型形參)不同而導致的不同抽取到新的模板(即traits)中去;然後通過traits的模板特化來實現針對具體情況的優化實現。Traits作為模板類,既聲明了統一的接口(包括類型、枚舉、函數方法等),又可以通過模板特化,針對不同數據類型或其他模板參數,為類、函數或者通用算法在因為使用的數據類型不同而導致處理邏輯不同時,提供了區分不同類型的具體細節,從而把這部分用Traits實現的功能與其它共同的功能區分開來。例如,容器的元素的不同數據類型,或者iostream是使用char還是wchar_t。一個traits包括了enum、typedef、模板偏特化(template partial specialization)。其中,enum定義了各種類的標識的統一表示;typedef定義了各個類的各自不同的類型定義,這對於使用模板元編程(template meta-programming)的靈活性非常重要;模板偏特化用於實現各個類的不同功能。

示例

[編輯]

假設有一個容器模板類,其包含元素的值類型可以是內生(built-in)的數據類型,也可以是自定義的類。因此,有的值類型支持move操作,有的值類型不支持move操作。該容器模板類具有統一的界面,但對不同的值類型實現了不同的語義功能。為此:

#include <iostream>

struct no_move{};//两个marker类型
struct has_move{};

struct myValueType{
  public: void move(){std::cout<<"move a myValueType obj."<<std::endl;}
};

template <typename T> struct traits{
  typedef no_move move_method; //对于traits模板类,默认为无move方法
  void move(T* p){}//默认为无move方法
};

template <> struct traits<myValueType>{
  typedef has_move move_method;//对于myValueType,traits模板偏特化,定义了有move方法
  void move(myValueType* p){p->move();} //模板特化,有move方法
};

template <typename T> struct Container{
  void move(T* p){traits<T>().move(p);};
};

int main()
{
  int i=101;
  int *p1=&i;
  myValueType v1;
  myValueType *pv=&v1;
  Container<int> c1;
  Container<myValueType> c2;
  c1.move(p1);
  c2.move(pv);
}

C#的支持

[編輯]

從C# 8.0開始,支持「缺省接口方法」( default interface methods)。

using System;

namespace CSharp8NewFeatures
{
    interface ILogger
    {
        // Traditional interface methods
        void Log(string message);
        void LogError(Exception exception);

        // Default interface method
        void LogWarning(string message)
        {
            Console.WriteLine(message);
        }        
    }

    class Logger : ILogger
    {
        public void Log(string message)
        {
            Console.WriteLine(message);
        }

        public void LogError(Exception exception)
        {
            Console.WriteLine(exception.ToString());
        }
    }

    class Program
    {
        static void Main(string[] args)
        {
            ILogger logger = new Logger();

            logger.LogWarning("Some warning message");
        }
    }
}

Haskell

[編輯]

Haskell中,traits稱作類型類(Type classes).

Java

[編輯]

從Java 8開始,支持缺省方法(default method)

JavaScript

[編輯]

可以通過functions與delegations實現,或者通過支持traits的庫。

Python

[編輯]

通過第三方庫py3traits,或者高階mixin類。