기고글 토론 "MQL5에서 테이블 모델 구현: MVC 개념 적용"

 

새로운 기고글 MQL5에서 테이블 모델 구현: MVC 개념 적용 가 게재되었습니다:

이 글에서는 MVC(모델-뷰-컨트롤러) 아키텍처 패턴을 사용하여 MQL5에서 테이블 모델을 개발하는 프로세스에 대해 살펴보겠습니다. 우리는 이를 통해 데이터 논리, 표현, 제어를 분리하고, 구조화되고 유연하며 확장 가능한 코드를 작성할 수 있습니다. 연결 리스트를 사용하여 데이터를 저장하는 것을 포함하여 테이블 모델을 구축하기 위한 클래스를 구현해 볼 것입니다.

프로그래밍에서 애플리케이션 아키텍처는 안정성, 확장성, 지원 용이성을 보장하는 데 중요한 역할을 합니다. 이러한 목표를 달성하는 데 도움이 되는 접근 방식 중 하나는 MVC(모델-뷰-컨트롤러) 라는 아키텍처 패턴을 활용하는 것입니다.

MVC 개념을 사용하면 애플리케이션을 세 가지의 상호 연관된 구성 요소, 즉 모델 (데이터 및 로직 관리), (데이터 표시), 컨트롤러 (사용자 작업 처리)로 나눌 수 있습니다. 이러한 분리를 통해 코드 개발, 테스트, 유지관리가 간소화되어 코드가 더욱 체계적이고 유연 해집니다.

이 글에서는 MQL5 언어로 테이블 모델을 구현하기 위해 MVC 원칙을 적용하는 방법을 살펴보겠습니다. 테이블은 데이터를 저장, 처리, 표시하는 데 중요한 도구이며 테이블을 올바르게 구성하면 정보를 처리하는 작업이 훨씬 쉬워질 수 있습니다. 테이블 작업을 위해 테이블 셀, 행, 테이블 모델 등의 클래스를 만들겠습니다. 테이블 모델 내의 행과 행 내에 셀을 저장하기 위해 MQL5 표준 라이브러리의 linked list(연결 목록) 클래스를 사용합니다. 이 클래스를 사용하면 데이터를 효율적으로 저장하고 사용할 수 있습니다.


작성자: Artyom Trishkin

 

안녕하세요, Artem입니다.

질문이 있습니다:

코드에서 객체 유형을 읽습니다.

      //--- 개체 유형 읽기
      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);
//--- 시작 마커 읽기 및 확인 - 0xFFFFFFFFFFFFFFFFFFF
   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++)
     {
      //--- 오브젝트 데이터 시작 마커 읽기 및 확인 - 0xFFFFFFFFFFFFFFFFFFFFF
      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()읽기 및 유형검사 메서드의 유형과 일치합니까? 그렇게 번역되나요?
그리고 유형을 확인하지 않고 그냥 읽습니다.

그렇다면 이 검사의 깊은 의미는 무엇일까요?

 
Alexey Viktorov #:
이 검사의 깊은 의미는 무엇일까요?

바로 이 일부 오브젝트의 Load() 메서드를 호출하여 파일에서 일부 오브젝트의 클래스를 로드할 때, "내가 정말 파일에서 나 자신을 읽었나?"(질문하신 내용)를 확인합니다. 그렇지 않다면 뭔가 잘못되었다는 뜻이므로 더 이상 로드할 필요가 없습니다.

여기에는 파일에서 객체 유형을 읽는 리스트(CListObj)가 있습니다. 이 목록은 파일에 무엇이 있는지(어떤 객체인지) 알지 못합니다. 하지만 CreateElement() 메서드에서 객체 유형을 생성하려면 이 객체 유형을 알고 있어야 합니다. 그렇기 때문에 파일에서 로드된 객체의 유형을 확인하지 않습니다. 결국 이 메서드에서는 객체가 아닌 목록의 유형을 반환하는 Type()과 비교하게 됩니다.

 
Artyom Trishkin #:

바로 이 일부 오브젝트의 Load() 메서드를 호출하여 파일에서 일부 오브젝트의 클래스를 로드하면 "내가 정말 파일에서 나 자신을 읽었나?"를 확인합니다(질문하신 내용입니다). 그렇지 않다면 뭔가 잘못되었다는 뜻이므로 더 이상 로드할 필요가 없습니다.

여기에는 파일에서 객체 유형을 읽는 LIST(CListObj)가 있습니다. 이 목록은 파일에 무엇이 있는지(어떤 객체인지) 알지 못합니다. 하지만 CreateElement() 메서드에서 객체 유형을 생성하려면 이 객체 유형을 알고 있어야 합니다. 그렇기 때문에 파일에서 로드된 객체의 유형을 확인하지 않습니다. 결국 이 메서드에서는 객체가 아닌 목록의 유형을 반환하는 Type()과 비교하게 됩니다.

고마워요, 이제 알겠습니다.

 

읽고 또 읽었습니다.

는 MVC에서 "모델"이 아닌 다른 것입니다. 예를 들어 일부 ListStorage는

 
본론으로 들어가 보겠습니다. 의견을 말하지 마세요.
 
궁금합니다. 이런 식으로 파이썬과 R 데이터 프레임의 아날로그를 얻을 수 있나요? 서로 다른 열에 서로 다른 유형의 데이터(제한된 유형 집합에서 문자열 포함)가 포함될 수 있는 테이블입니다.
 
Aleksey Nikolayev #:
궁금합니다. 이런 식으로 파이썬과 R 데이터 프레임의 아날로그를 얻을 수 있나요? 이러한 테이블은 서로 다른 열에 서로 다른 유형의 데이터(제한된 유형 집합에서 문자열 포함)가 포함될 수 있는 테이블입니다.

가능합니다. 한 테이블의 다른 열에 대해 이야기하는 경우 설명 된 구현에서 테이블의 각 셀은 다른 데이터 유형을 가질 수 있습니다.