天天看點

STK Component:Evaluator pattern(電腦模式)C# 中的枚舉器Evaluator模式AxesLinearRate類的Evaluator代碼實作其他Evaluator

在STK Component中廣泛的利用我們稱之為的”電腦模式”。在Component中做任何計算時幾乎都需要使用電腦模式。

所謂電腦模式,簡單的說就是将一個對象的定義和其計算分離開。對象本身隻儲存資料,并不實際執行任何計算。從對象中擷取其對應的電腦,然後利用電腦執行與該對象有關的計算。

C# 中的枚舉器

其實在學習C#中,我們已經遇到過電腦模式,這就是C#中的枚舉器。讓我們來重新溫習一下,有助于了解電腦模式。

下面幾個連結都是闡述電腦模式的,如果對枚舉器不熟悉的可以參考。

http://www.cnblogs.com/JimmyZhang/archive/2007/08/22/865245.html

http://blog.csdn.net/jiangxinyu/article/details/8554818

面向對象設計原則中有一條是類的單一職責原則,是以我們要盡可能的去分解這些職責,用不同的類去承擔不同的職責。Iterator模式就是分離了集合對象的周遊行為,抽象出一個疊代器類來負責,這樣既可以做到不暴露集合的内部結構,又可讓外部代碼透明的通路集合内部的資料。

以自定義的字元串數組類為例,示例代碼如下:

//  自定義的類,實作字元串數組的功能(僅展示關鍵代碼,其餘省略)
    public class MyStringList : IEnumerable<string>
    {
        //  内部數組,用來儲存字元串
        string[] strings;

        //  此類的其他屬性及方法
        //...

        //------------------------------------------------------------
        //  Ienumerble<T>接口的實作,傳回實作IEnumerator<T>接口的對象
        public IEnumerator<string> GetEnumerator()
        {
            return new MyStringListEnumerator(strings);
        }

        //------------------------------------------------------------
        // 嵌套的私有ListBoxEnumerator類實作
        private class MyStringListEnumerator : IEnumerator<string>
        {
            string[] mystrs;

            //  構造函數
            MyStringListEnumerator(string[] strs)
            {
                this.mystrs = strs;
            }

            // 接口IEnumerator的代碼實作: Current/MoveNext/Reset..            
            //...
        }
    }


    //  使用方法:
    //  建立對象
    MyStringList myList = new MyStringList();
    //  擷取對象的IEnumerator
    IEnumerator<string> myEnumerator = myList.GetEnumerator();
    //  使用IEnumerator的相關功能
    myEnumerator.MoveNext();
    //...
           

類MyStringList的内部字段strings儲存着字元串的數組,同時有個内部的類MyStringListEnumerator來實作IEumerator接口。外部通過類的GetEnumerator()函數來獲得實作接口IEnumerator的對象myEnumerator,注意,外部無法直接建立MyStringListEnumerator對象,是由GetEnumerator()函數擷取的,擷取後即可通過myEnumerator調用相關的功能(如Current,MoveNext,Reset)。

類MyStringList負責對象的模組化,這個例子中,就是通過内部的數組儲存字元串數組;類MyStringListEnumerator負責對象的功能(如MoveNext等),外部對其不可見,由類MyStringList内部進行實作。通過這兩個類把兩者的職責分離開來,兩者又互相聯系,都是通過内部的數組(strings和mystrs,其實兩個數組是同一個)來聯系的。

Evaluator模式

先來看一個STK Component中Evaluator的例子,以坐标系轉換為例。

//  建立新的坐标系
AxesLinearRate axes = new AxesLinearRate();
//  以J2000的坐标系作為新坐标系axes的參考基準(舊坐标系)
axes.ReferenceAxes = CentralBodiesFacet.GetFromContext().Earth.J2000Frame.Axes;
//  初始時刻
axes.ReferenceEpoch = TimeConstants.J2000;
//  初始時刻:新坐标系相對舊坐标系的旋轉(此處為機關陣,也就是說初始時刻兩個坐标系重合)
axes.InitialRotation = UnitQuaternion.Identity;
//  新坐标系相對舊坐标系的旋轉角速度(rad/s)
axes.InitialRotationalVelocity = ;
//  新坐标系相對舊坐标系的旋轉角加速度(rad/s^2)
axes.RotationalAcceleration = ;
//  新坐标系相對舊坐标系的旋轉矢量,此矢量在舊坐标系中表達(此處為繞舊坐标系的X軸旋轉)
axes.SpinAxis = new UnitCartesian(, , );

//  ***以上定義了一個新的坐标系,從其定義參數,理論上我們可以求出在任意時刻,舊坐标系到新坐标系的轉換矩陣
//----------------------------------------------------------------------------------
//  ***以下為計算舊坐标系到新坐标系的轉換矩陣

//  從新坐标系對象擷取evaluator
AxesEvaluator evaluator = axes.GetEvaluator();
JulianDate dateToEvaluate = new JulianDate(new GregorianDate(, , , , , ));
//  使用獲得的evaluator計算某時刻的舊坐标系到新坐标系的轉換矩陣(機關四元素形式)
UnitQuaternion rotationFromJ2000 = evaluator.Evaluate(dateToEvaluate);
           

上面的例子中,建立了一個坐标系對象axes,并計算其基準坐标系(舊坐标系)到它的轉換矩陣。可以看出,axes對象僅僅用來描述一個新的坐标系是如何指向的(相對舊坐标系而言),而從舊坐标系到新坐标系的轉換計算工作是由另一個類來實作的,它就是AxesEvaluator,是通過axes對象的GetEvaluator()方法來擷取的。由AxesEvaluator類的函數Evaluate(JulianDate date)來計算兩個坐标系的轉換關系。這種将對象的定義和其計算功能分開就是STK Component中的Evaluator模式。

可以推測的是AxesEvaluator對象evaluator中必然保留或者直接指向axes中的相關定義參數,否則evaluator無法計算兩個坐标系的轉換。

AxesLinearRate類的Evaluator代碼實作

還是以坐标系AxesLinearRate類為例,通過.Net Reflector軟體看看其源代碼,進而了解其内部機制。

//  線性旋轉坐标系類(繼承自基類:Axes)
public class AxesLinearRate : Axes
{
    // 屬性,描述相對舊坐标系的一系列屬性參數
    // Properties
    public UnitQuaternion InitialRotation { get; set; }
    public double InitialRotationalVelocity { get; set; }
    // **參考坐标系,也就是舊坐标系
    public Axes ReferenceAxes { get; set; }
    public JulianDate ReferenceEpoch { get; set; }
    public double RotationalAcceleration { get; set; }
    public UnitCartesian SpinAxis { get; set; }

    // Methods
    // ...一系列override基類Axes的方法    
    //
    // **注意,此内部方法中,實際建立AxesEvaluator
    private AxesEvaluator CreateEvaluator(EvaluatorGroup group)
    {
      return new Evaluator(this.m_referenceAxes, this.m_epoch, this.m_initialRotation, this.m_spinAxis, this.m_initialRotationalVelocity, this.m_constantRotationalAcceleration);

    }
    // ... 
    public override AxesEvaluator GetEvaluator(EvaluatorGroup group);

    //------------------------------------------------------------------
    // **注意,由内部類來實作AxesEvaluator
    // 類Evaluator的名字可以取任何值,反正外部看不到,在外部,是以基類AxexEvaluator來代替。
    private class Evaluator : AxesEvaluator
    {
        // **看看這裡的内部參數,是不是和類AxesLinearRate的屬性參數基本一緻??!!
        // 隻要靠這些參數,它才能知道怎麼計算兩個坐标系的轉換!!
        // Fields
        private double m_constantRotationalAcceleration;
        private JulianDate m_epoch;
        private UnitQuaternion m_initialRotation;
        private double m_initialRotationalVelocity;
        private Axes m_referenceAxes;
        private UnitCartesian m_spinAxis;

        // Methods
        // 這個構造函數在私有方法CreateEvaluator中被調用
        public Evaluator(Axes referenceAxes, JulianDate epoch, UnitQuaternion initialRotation, UnitCartesian spinAxis, double initialRotationalVelocity, double constantRotationalAcceleration);

        // **最重要方法!!!用來計算從舊坐标系到此坐标系的轉換,此方法内部的代碼就是具體的計算過程!
        public override UnitQuaternion Evaluate(JulianDate date);
        public override Motion<UnitQuaternion, Cartesian> Evaluate(JulianDate date, int order);
       //...其他方法

        // 這個屬性用來儲存舊坐标系
        public override TimeIntervalCollection<Axes> DefinedInIntervals { get; }
        // ...        
    }
}
           

首先類AxesLinearRate是繼承基類Axes,實際上所有的坐标系都繼承自Axes。類AxesLinearRate的一個重要方法就是GetEvaluator,用來擷取其計算類AxesEvaluator對象。而AxesEvaluator的類的實作是由内部類Evaluator來實作的。

在内部類Evaluator中,儲存了類AxesLinearRate的相關參數,以及用于計算坐标系轉換的方法:Evaluate,其傳回值為UnitQuaternion或Motion

其他Evaluator

對于每個繼承自Axes的類來說,其電腦類都為AxesEvaluator,由繼承類負責實作AxesEvaluator類的實作,其Evaluate方法的傳回值為UnitQuaternion。而對于其它類型,其電腦架構與其類似。見下圖。

STK Component:Evaluator pattern(電腦模式)C# 中的枚舉器Evaluator模式AxesLinearRate類的Evaluator代碼實作其他Evaluator

Axes、Point、Vector分别表示坐标系、點、矢量的基類,都包含一個GetEvaluator的方法,不同的是對應不同的類型其傳回值也不同,分别為AxesEvaluator、PointEvaluator和VectorEvaluator,每個Evaluator的方法Evaluate的傳回值也根據其類型不同而不同。

在自己以這些基類建立相應的具體類時,需要自行實作其對應的Evaluator。

繼續閱讀