다른 질문에 대한 후속 조치 ( 입력 파일에서 모델 데이터 읽기에 대한 설계 결정하기 ).
제작자 또는 공장 패턴에 대해 다른 질문을하고 싶습니다. (빌더가 팩토리보다 더 복잡하다는 것을 읽었으며 지금은 빌더를 사용할 필요가 없을 수도 있습니다). 그래서 제가 읽어야 할 데이터는 다음과 같습니다.
TABLE: "DEGREES OF FREEDOM" X=Yes Y=Yes Z=Yes R1=Yes R2=Yes R3=Yes TABLE: "ANALYSIS OPTIONS" Solver=Advanced SolverProc=Advanced TABLE: "COORDINATE SYSTEMS" Name=GLOBAL Type=Cartesian X=0 Y=0 Z=0 TABLE: "GRID LINES" CoordSys=GLOBAL AxisDir=X GridID=A XRYZCoord=-720 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=B XRYZCoord=-432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=C XRYZCoord=-144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=D XRYZCoord=144 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=E XRYZCoord=432 LineColor=Gray8Dark Visible=Yes CoordSys=GLOBAL AxisDir=X GridID=F XRYZCoord=720 LineColor=Gray8Dark Visible=Yes ...
이러한 테이블이 더 많이 있습니다. 일부 테이블에는 상위, 하위 관계가 있습니다 (각 좌표계에는 자체 그리드 선이 있음). 다음과 같이 각 테이블을 나타내는 구조를 만들었습니다.
struct ActiveDOF { bool Ux; bool Uy; bool Uz; bool Rx; bool Ry; bool Rz; }; struct GridLine { enum Direction{X, Y, Z}; enum Type{PRIMARY, SECONDARY}; enum Location{START, END}; std::string coodSystem; Direction direction; std::string gridID; float XRYZ; Type lineType; QColor color; bool visible; Location bubleLoc; bool allVisible; float bubleSize; }; struct CoordinateSystem { std::string name; std::string type; QVector3D center; // center x, center y, cetner z QVector3D about; // aboutx, about y, about z std::vector<GridLine> gridLines; };
이러한 데이터 구조는 모델 클래스에 통합되어 있습니다. 다음과 같은 50 개의 이상한 데이터 구조 :
class Model { private: ActiveDOF activeDOF; CoordinateSystem coordinateSystem; .... public: Model() {} ... }
각 테이블에는 set 메서드와 get 메서드가 있어야합니다. 이 디자인을 변경하면 시간이 많이 걸리기 때문에 걱정이됩니다. 어떤 제안이라도 감사합니다. 여기에있는 정보도 이전 질문을 더 잘 이해할 수 있다고 생각합니다.
지금은 상황을 고려할 때 빌더 또는 팩토리 메소드가 어디로 가야할지 모르겠습니다. 코드와 UML 차트를 살펴 보았지만 팩토리 또는 빌더를 구현하는 방법을 이해할 수 없었습니다. 디자인에 필요한 구조를 만들기 위해 각 테이블에 이름으로 액세스 할 수 있어야합니다. 모델 내에서 변경 될 수 있기 때문에 각 테이블을 가상 기본 클래스의 하위 클래스로 만드는 것을 당분간 피하고 있습니다. 그래서 컨테이너에 저장할 수 있습니다.
또한 데이터 구조체의 인스턴스를 선언하는 대신 포인터를 유지해야한다는 것이 의미가 있습니까? 모든 데이터 구조가 a에서 파생 된 경우 Record라는 가상 기본 클래스를 사용하면 모델은 다음과 같습니다.
class Model { private: ActiveDOF* activeDOF; CoordinateSystem* coordinateSystem; .... std::Vector<Record*> data; public: Model() {} ... }
메모리를 할당하고 배치하는 것이 추가 작업이라고 생각하지만 데이터를 관리하고 추가 입력을 유지하는 데 도움이 될 수 있습니까?
댓글
답변
데이터 액세스 문제를 해결하려고합니다. 데이터 액세스 솔루션이 필요합니다.
먼저 제안 된 솔루션과 문제가 해결되지 않는 이유를 살펴 보겠습니다.
팩토리 패턴
팩토리 디자인 패턴 (팩토리 메소드 패턴이라고도 함)은 다형성을 활용하고 구현 클래스에서 객체 생성을 완전히 분리하려는 경우에 유용합니다.
수업 기반 프로그래밍에서 팩토리 메소드 패턴은 생성 패턴입니다 는 팩토리 메소드를 사용하여 객체를 지정하지 않고도 객체를 생성하는 문제를 처리합니다. 생성 될 개체의 정확한 클래스. 이는 팩토리 메소드를 호출하여 개체를 생성하여 — 인터페이스 및 하위 클래스에 의해 구현되거나 기본 클래스에서 구현되고 생성자를 호출하는 대신 파생 클래스에 의해 선택적으로 재정의 됨 — .
(강조, 내)
그리고 아래에서 자세히 설명합니다. 이 패턴으로 해결되는 문제 :
Factory Method 디자인 패턴은 다음과 같은 문제를 해결합니다.
- 객체를 어떻게 생성 할 수 있습니까? 하위 클래스 가 인스턴스화 할 클래스를 재정의 할 수 있도록?
- 클래스가 하위 클래스에 대한 인스턴스화를 어떻게 연기 할 수 있습니까?
질문에 설명하는 문제가 이것과 다릅니다. 당신은 하위 클래스 나 다형성을 다루지 않습니다. 공장 패턴은 해결책이 아닙니다.
Builder 패턴
The Builder 패턴 (출처 : Wikipedia ) :
Builder는 객체 지향 프로그래밍에서 다양한 객체 생성 문제에 대한 유연한 솔루션을 제공하도록 설계된 디자인 패턴입니다. Builder 디자인 패턴의 의도는 복잡한 개체의 구성과 표현을 분리하는 것입니다.
(강조, 내)
여기서도 설명하는 문제와이 패턴의 의도 된 용도가 일치하지 않습니다.
Builder 디자인 패턴은 다음과 같은 문제를 해결합니다.
- 클래스 (동일한 구성 프로세스)가 복잡한 개체 ?
- 복잡한 개체 단순화 하시겠습니까?
(강조, 내)
여기서 핵심은 객체 (객체 = 1 객체)의 구성이 복잡하다는 것입니다. 이는 생성자 인수의 수가 많거나 종속성을 조합하는 복잡성 때문일 수 있습니다.
개별적으로 각 구조체 또는 클래스는 매우 간단하므로 빌더 패턴도 적합하지 않습니다.
데이터 액세스 패턴 (솔루션)
실제로 해결하려는 문제는 데이터 액세스를 수행하는 방법입니다. 데이터 액세스 개체 .
컴퓨터 소프트웨어에서 데이터 액세스 개체 (DAO) 특정 유형의 데이터베이스 또는 기타 지속성 메커니즘에 추상 인터페이스를 제공하는 개체입니다. 애플리케이션 호출을 지속성 계층에 매핑하여 , DAO 는 데이터베이스 세부 정보를 노출하지 않고 특정 데이터 작업을 제공합니다.
귀하의 경우 “데이터베이스”를 “텍스트 파일”로 바꿉니다. 관련 디자인 패턴은 저장소 디자인 패턴 으로, 데이터 액세스를 3 가지 주요 솔루션으로 나눕니다.
- 저장소 — “데이터 액세스 항목”을위한 공용 인터페이스
- 게이트웨이 —는 Oracle 데이터베이스와 통신하거나 읽기 / 쓰기하는 방법을 알고 있습니다. 텍스트 파일. 여기에는 SQL 또는 텍스트 파일에 예상되는 데이터 형식에 대한 객체 및 구조체 직렬화가 포함됩니다.
- Factory —는 게이트웨이에서 반환 된 데이터를 객체 및 구조체에 매핑합니다. 나머지 애플리케이션에서 사용
메모리 소유권
메모리 자동 관리의 장점 / 제한이 없기 때문에 할당 된 메모리 소유권 이러한 객체와 구조체는 확실히 문제입니다. 여기에서 결정을 내려야합니다.
- 데이터 액세스 객체가이 메모리를 정리해야합니까?
- 데이터 액세스 객체가 호출자 (클라이언트 코드)가이 메모리를 해제 할 책임이 있습니까?
애플리케이션이 시작될 때 데이터 액세스 개체가 생성되고 애플리케이션이 종료 될 때까지 유지되는 경우 데이터 액세스 개체가이 메모리의 소유권을 가질 수 있습니다.
데이터 액세스 개체가 요청시 생성 된 다음 폐기되는 경우 클라이언트 코드는이 메모리가 clea인지 확인해야합니다. ned up.
데이터 액세스 개체에 대한 주석 또는 문서에서이를 정의하고 코드 검토에서이를 적용합니다.
Comments
- 이 접근 방식이 마음에 듭니다. 훨씬 더 유연 해 보입니다. 내가 묻는 다른 것은 그 문제에 대한 나의 무지를 드러 낼 것입니다. DAO를 직접 구현해야합니까? 내가 이해하는 방식으로 게이트웨이와 공장을 작성해야합니까? 게이트웨이는 브리지 GOF 패턴과 동일합니까?
- 저장소 패턴의 게이트웨이는 브리지 패턴의 또 다른 변형이라고 말할 수 있습니다. 실제로 리포지토리 패턴의 기반은 특히 데이터 액세스에 초점을 맞춘보다 체계적이고 조정 된 브리지 패턴 인 것처럼 보입니다. 그리고 예, ‘이 구성 요소를 직접 작성해야합니다.
- 게시 한 링크를 따라 en.wikipedia.org/wiki/ODB_(C%2B%2B) ,이 ODB가 그림에 어떻게 들어 맞습니까? 내 텍스트 입력을 sqllite로 변환 한 다음 지속성을 위해 ODB를 사용하는 프로그램을 작성할 수 있습니까? 이 소리인가요? 나는 방금 ODB를 우연히 발견하고 두 가지 예를 보았으므로 정보에 입각 한 의견이 아닙니다.
- 코드 작성 지원은이 사이트의 주제가 아니지만 ‘ 텍스트를 sqlite로 변환하고 기존 라이브러리를 사용할 수 있습니다.
답변
빌더는 공장 불변 (메소드) 내에서 “빌드”되어 텍스트 파일을 읽습니다. 당신은 말한 파일을 읽는 방법으로 1 개의 팩토리를 작성할 것입니다. 이제 읽은 데이터 (중첩 된 데이터 생각)에서 모델을 점진적으로 빌드해야하는 경우 팩토리 메서드 내부의 빌더 패턴이 도움이 될 것입니다. 그러나 단일 모델로 데이터를로드하는 것으로 충분할 것입니다.
댓글
- 일부 의사 코드는 매우 도움이 될 수 있습니다. 이전에 팩토리 또는 빌더 패턴을 사용한 적이 없습니다.
답변
구조의 크기와 복잡성을 감안할 때 특히 모델이 변경 불가능한 경우 (또는 만들 수있는 경우) 빌더가 가장 적절 해 보입니다. 빌더와 모델 사이의 긴밀한 결합을 받아 들여야하지만 특히 여러 위치에서 모델을 빌드해야하는 경우에는 문제가 될 가치가 있습니다. 빌더를 사용하면 유효성 검사를 캡슐화 할 수도 있습니다.
그러나 모델이 변경 가능하고 한곳에서만 생성되는 경우 공장이 더 적절하고 편리 할 수 있으며 YAGNI가 작동합니다.
다른 질문에 대한 응답으로 , C ++에 원시 포인터를 저장해서는 안됩니다. 사실 std::unique_ptr
에는 단점이 없으며 객체 파괴를 쉽게 처리합니다. 벡터가 범위를 벗어나면 메모리를 해제하지 않습니다. 작성된대로 참조하지만 unique_ptr을 사용하면됩니다.
특히 수량이 변경 될 가능성이있는 경우 대량의 반복 요소에 대한 벡터를 생성하지만 공유되지 않는 중간 크기 구성 요소의 경우 구조체에 직접 포함하는 것이 좋습니다.
Model
클래스 (또는 공통 기본 클래스ModelBase
또는IModel
)의 다른 파생) 및 인스턴스화되는 구체적인 파생에 대한 결정을 중앙 집중화하려고합니다. ‘ 귀하의 질문에이 문제가 없습니다. 그래서 여기에서 공장을 사용하는 방법에 대한 아이디어가 ‘ 무엇입니까?