記事「MQL5でのテーブルモデルの実装:MVC概念の適用」についてのディスカッション

 

新しい記事「MQL5でのテーブルモデルの実装:MVC概念の適用」はパブリッシュされました:

本記事では、MQL5におけるテーブルモデルの開発過程を、MVC (Model-View-Controller)アーキテクチャパターンを用いて解説します。データロジック、表示、制御を分離することで、構造化され柔軟かつ拡張可能なコードを実現します。テーブルモデルを構築するためのクラス設計や、データ格納のためのリンクリストの使用方法も取り上げます。

プログラミングにおいて、アプリケーションのアーキテクチャは、信頼性、拡張性、保守性を確保する上で非常に重要です。これらの目的を達成する手法のひとつが、MVC (Model-View-Controller)と呼ばれるアーキテクチャパターンの活用です。

MVCの概念は、アプリケーションを3つの相互関連するコンポーネントに分割します。モデル(データとロジックの管理)、ビュー(データの表示)、コントローラー(ユーザー操作の処理)です。この分離により、コードの開発、テスト、保守が容易になり、より構造化され柔軟な設計が可能になります。

本記事では、MQL5言語にMVCの原則を適用してテーブルモデルを実装する方法を考えます。テーブルはデータの格納、処理、表示において重要なツールであり、適切に組織化することで情報の扱いやすさが大きく向上します。テーブルを扱うためのクラスとして、テーブルセル、行、テーブルモデルを作成します。また、行内のセルやテーブルモデル内の行の格納には、MQL5標準ライブラリのリンクリストクラスを使用し、効率的なデータ格納と操作を可能にします。


作者: Artyom Trishkin

 

こんにちは、アルテム。

質問があります:

あなたのコードはオブジェクトタイプを読み取ります。

      //--- オブジェクト・タイプの読み取り
      this.m_element_type=(ENUM_OBJECT_TYPE)::FileReadInteger(file_handle,INT_VALUE);

しかし、SBのようにチェックされていません。

bool CList::Load(const int file_handle)
  {
   uint     i,num;
   CObject *node;
   bool     result=true;
//--- チェック
   if(file_handle==INVALID_HANDLE)
      return(false);
//--- 開始マーカーの読み取りとチェック - 0xFFFFFFFFFFFFFFFFF
   if(FileReadLong(file_handle)!=-1)
      return(false);
//---タイプの読み取りとチェック
   if(FileReadInteger(file_handle,INT_VALUE)!=Type())
      return(false);
//--- リストのサイズを読み込む
   num=FileReadInteger(file_handle,INT_VALUE);
//--- メソッドLoad()の呼び出しを使って、リスト項目を順次作成する。
   Clear();
   for(i=0;i<num;i++)
     {
      node=CreateElement();
      if(node==NULL)
         return(false);
      Add(node);
      result&=node.Load(file_handle);
     }
//--- 成功
   return(result);
  }

見てわかるように、Type()メソッドは単に値を返します。

   virtual int       Type(void) const { return(0x7779); }

SBではこのようなチェックは必要なのでしょうか?型を読み取り、対応する型の要素を作成するだけで本当に十分なのでしょうか?

 
Alexey Viktorov #:
this.m_element_type=(ENUM_OBJECT_TYPE)::FileReadInteger(file_handle,INT_VALUE);

さて、型が読み込まれなかったら、次はどうする?

これがそのコードだ:

//--- ノード・オブジェクトの Load() メソッドを呼び出して、リスト項目を逐次再作成する。
   this.Clear();
   for(uint i=0; i<num; i++)
     {
      //--- オブジェクト・データのスタート・マーカーを読み取り、チェックする - 0xFFFFFFFFFFFFFFFFFFF
      if(::FileReadLong(file_handle)!=MARKER_START_DATA)
         return false;
      //--- オブジェクト・タイプの読み取り
      this.m_element_type=(ENUM_OBJECT_TYPE)::FileReadInteger(file_handle,INT_VALUE);
      node=this.CreateElement();
      if(node==NULL)
         return false;
      this.Add(node);
      //--- これで、ファイル・ポインターはオブジェクト・マーカーの先頭から12バイト(8-マーカー、4-タイプ)だけ相対的にオフセットされる。
      //--- オブジェクト・データの先頭にポインタを置き、ノード要素のLoad()メソッドを使ってファイルからオブジェクト・プロパティをロードしてみましょう。
      if(!::FileSeek(file_handle,-12,SEEK_CUR))
         return false;
      result &=node.Load(file_handle);
     }
//--- 結果
   return result;
  }
//+------------------------------------------------------------------+
//| リスト項目の作成方法|
//+------------------------------------------------------------------+
CObject *CListObj::CreateElement(void)
  {
//--- m_element_typeのオブジェクト・タイプに応じて、新しいオブジェクトを作成する。
   switch(this.m_element_type)
     {
      case OBJECT_TYPE_TABLE_CELL   :  return new CTableCell();
      case OBJECT_TYPE_TABLE_ROW    :  return new CTableRow();
      case OBJECT_TYPE_TABLE_MODEL  :  return new CTableModel();
      default                       :  return NULL;
     }
  }

オブジェクトの型を変数に読み込む。次に、CreateElement()でこのオブジェクトを作成しようとする。作成されるオブジェクトの型がファイルから読み取られなかった場合、このメソッドは何を返すでしょうか?

 
Artyom Trishkin #:

さて、タイプが読まれなかったら、次はどうする?

これがそのコードだ:

オブジェクトの型を変数に読み込みます。次に、CreateElement()でこのオブジェクトを作成しようとする。作成されるオブジェクトの型がファイルから読み取られなかった場合、このメソッドは何を返すでしょうか?

アーテム、私が話しているのはそういうことではない。SBには型チェックがあるという事実を話しているんだ。まさにそのチェックだ。

//---タイプの読み取りとチェック
   if(FileReadInteger(file_handle,INT_VALUE)!= Type())
      return(false);

ファイルから読み込まれた型が、Type()Readとチェック メソッドから読み込まれた型と一致するかどうか。そう変換されるのか?
そして、それをチェックせずにただ型を読み取る。

そこで疑問なのは、このチェックの深い意味は何なのかということだ。

 
Alexey Viktorov #:
このチェックの深い意味は何だろう?

SomeObjectのクラスがファイルからロードされるとき、まさにこのSomeObjectのLoad()メソッドを呼び出すと、"本当にファイルから自分自身を読み込んだのか?"をチェックする(それがあなたが尋ねていることだ)。もしそうでなければ、何かが間違っていることを意味するので、それ以上ロードする意味はない。

ここにあるのは、ファイルからオブジェクト・タイプを読み込んでいるリスト(CListObj)だ。リストは、ファイルに何があるか(どんなオブジェクトか)を知らない。しかし、CreateElement()メソッドでオブジェクトを作成するには、このオブジェクト・タイプを知っていなければなりません。だから、ファイルから読み込まれたオブジェクトの型をチェックしないのです。結局のところ、このメソッドではオブジェクトではなくリストの型を返すType()と比較することになる。

 
Artyom Trishkin #:

このSomeObjectのLoad()メソッドを呼び出すことで、SomeObjectのクラスがファイルからロードされると、「本当にファイルから読み込んだのか?もしそうでなければ、何かが間違っていたことを意味するので、それ以上ロードする意味はない。

ここにあるのは、ファイルからオブジェクト・タイプを読み込むリスト(CListObj)だ。リストは、ファイルに何があるか(どんなオブジェクトか)を知らない。しかし、CreateElement()メソッドでオブジェクトを生成するためには、このオブジェクト・タイプを知っていなければなりません。だから、ファイルから読み込まれたオブジェクトの型をチェックしないのです。結局のところ、このメソッドではオブジェクトではなくリストの型を返すType()と比較することになる。

ありがとう、わかりました。

 

私はそれを読み、そしてまた読み直した。

MVCにおける "モデル "以外の何物でもない。例えば

 
本題に入ろう。自分の意見は胸にしまっておけ。
 
どうだろう。この方法でpythonやRのデータフレームに類似したものを得ることは可能でしょうか?これらは、異なるカラムが異なる型のデータ(文字列を含む限られた型のセット)を含むことができるテーブルです。
 
Aleksey Nikolayev #:
どうだろう。この方法でpythonやRのdataframesに類似したものを得ることは可能でしょうか?このようなテーブルでは、異なるカラムに異なる型(文字列を含む限られた型)のデータを格納することができます。

できます。もし1つのテーブルの異なるカラムについて話しているのであれば、説明した実装ではテーブルの各セルは異なるデータ型を持つことができます。