태그 보관물: programming-practices

programming-practices

“심층 구성 계층 구조”도 나쁘지 않습니까? // … interface

“Composition Hierarchy”가 중요하지 않다면 사과하지만 질문에서 그 의미가 무엇인지 설명하겠습니다.

“상속 계층 구조 유지”또는 “상속보다 컴포지션 선호”등의 변형을 경험하지 않은 OO 프로그래머는 없습니다. 그러나 심층 구성 계층도 문제가있는 것 같습니다.

실험 결과를 자세히 설명하는 보고서 모음이 필요하다고 가정 해 보겠습니다.

class Model {
    // ... interface

    Array<Result> m_results;
}

각 결과에는 특정 속성이 있습니다. 여기에는 실험 시간과 실험의 각 단계에서 얻은 일부 메타 데이터가 포함됩니다.

enum Stage {
    Pre = 1,
    Post
};

class Result {
    // ... interface

    Epoch m_epoch;
    Map<Stage, ExperimentModules> m_modules;
}

큰 확인. 이제 각 실험 모듈에는 실험 결과를 설명하는 문자열과 실험 샘플 세트에 대한 참조 모음이 있습니다.

class ExperimentalModules {
    // ... interface

    String m_reportText;
    Array<Sample> m_entities;
}

그리고 각 샘플에는 … 글쎄요, 당신은 그림을 얻습니다.

문제는 응용 프로그램 도메인에서 객체를 모델링하는 경우 매우 자연스러운 것처럼 보이지만 하루가 끝나면 Result바보 같은 데이터 컨테이너입니다! 큰 클래스 그룹을 만드는 것은 가치가없는 것 같습니다.

위에 표시된 데이터 구조와 클래스가 응용 프로그램 도메인의 관계를 올바르게 모델링한다고 가정하면 심층적 인 구성 계층에 의존하지 않고 이러한 “결과”를 모델링하는 더 좋은 방법이 있습니까? 그러한 디자인이 좋은지 아닌지를 결정하는 데 도움이되는 외부 컨텍스트가 있습니까?



답변

이것이 Demeter법칙 / 최소한의 지식 원칙에 관한 것입니다. 사용자는 Model반드시 ExperimentalModules자신의 작업을 수행하기 위해 인터페이스에 대해 알아야 할 필요는 없습니다 .

일반적인 문제는 클래스가 다른 유형에서 상속되거나 일부 유형의 공개 필드가 있거나 메소드가 유형을 매개 변수로 사용하거나 유형을 반환 할 때 모든 유형의 인터페이스가 내 클래스의 효과적인 인터페이스의 일부가된다는 것입니다. 문제는 다음과 같습니다. 내가 의존하는 이러한 유형은 클래스의 요점을 사용합니까? 아니면 내가 실수로 노출 한 구현 세부 정보입니까? 그들이 구현 세부 사항이라면 방금 그것들을 공개했고 내 클래스의 사용자가 그것들에 의존 할 수있게 해 주었기 때문에 – 클라이언트는 이제 구현 세부 사항과 밀접하게 연결되어 있습니다.

따라서 응집력을 향상 시키려면 사용자가 내 개인 구조에 접근하도록 요구하는 대신 유용한 작업을 수행하는 더 많은 메소드를 작성하여이 결합을 제한 할 수 있습니다. 여기에서 결과를 검색하거나 필터링하는 방법을 제공 할 수 있습니다. 인터페이스를 변경하지 않고도 내부 표현을 변경할 수 있기 때문에 클래스 리팩토링이 쉬워집니다.

그러나 이것은 비용이 들지 않습니다. 노출 된 클래스의 인터페이스는 이제 항상 필요하지 않은 작업으로 인해 부풀어 오릅니다. 이는 인터페이스 분리 원칙을 위반합니다. 사용자가 실제로 사용하는 것보다 더 많은 작업에 의존하도록 강요해서는 안됩니다. 디자인 이 중요한 곳은 디자인 입니다. 디자인은 상황에 따라 어떤 원칙이 더 중요한지 결정 하고 적절한 절충안을 찾는 것입니다.

여러 버전에서 소스 호환성을 유지해야하는 라이브러리를 설계 할 때는 최소한의 지식 원칙을 더 신중하게 따르는 경향이 있습니다. 내 라이브러리가 다른 라이브러리를 내부적으로 사용하는 경우 해당 라이브러리에서 정의한 내용을 사용자에게 노출시키지 않습니다. 내부 라이브러리에서 인터페이스를 노출해야하는 경우 간단한 래퍼 객체를 만듭니다. Bridge Pattern 또는 Facade Pattern과 같은 디자인 패턴이 여기에 도움이 될 수 있습니다.

그러나 내 인터페이스가 내부적으로 만 사용되거나 노출 할 인터페이스가 매우 기본적인 경우 (표준 라이브러리의 일부 또는 변경이 불가능한 라이브러리의 기본 인 경우) 숨기는 것이 소용이 없을 수 있습니다 이러한 인터페이스. 평소와 같이, 하나의 크기에 맞는 답은 없습니다.


답변

“심층 구성 계층 구조”도 나쁘지 않습니까?

물론이야. 규칙은 실제로 “모든 계층을 가능한 한 평평하게 유지하십시오”라고 표시해야합니다.

그러나 딥 컴포지션 계층은 딥 상속 계층보다 덜 취약하며 변경하기가 더 유연합니다. 직관적으로 이것은 놀라운 일이 아닙니다. 가족 계층도 같은 방식입니다. 혈족과의 관계는 유전학에 고정되어 있습니다. 친구와 배우자와의 관계는 그렇지 않습니다.

귀하의 예는 “심층 계층 구조”라고 생각하지 않습니다. 양식은 x와 y 좌표에서 상속되는 일련의 점에서 상속되는 사각형에서 상속받으며 아직 증기의 전체 헤드를 얻지 못했습니다.


답변

아인슈타인의 역설 :

모든 계층을 가능한 한 평평하게 유지 하지만 평평하게 유지 하지 마십시오.

당신이 모델링하는 문제가 그런식이라면, 그것을 모델링하는 것에 대한 자격이 없어야합니다.

응용 프로그램은 거대한 스프레드 시트이므로 컴포지션 계층 구조를 그대로 모델링 할 필요가 없습니다. 그렇지 않으면하세요. 나는 그 일이 무한히 깊다고 생각하지 않습니다. 이러한 컬렉션을 채우는 것이 비싸면 컬렉션을 반환하는 게터를 데이터베이스에서 가져 오는 저장소에 요청하는 것과 같이 유지하십시오. 게으른 말은 필요할 때까지 채우지 마십시오.


답변

예, 관계형 테이블처럼 모델링 할 수 있습니다

Result {
    Id
    ModelId
    Epoch
}

프로그래밍이 쉬워지고 데이터베이스에 간단하게 매핑 될 수있는 그러나 당신의 관계의 하드 코딩을 잃는 대신에


답변

Java는 모든 것이 객체라는 아이디어를 바탕으로 구축 되었기 때문에 Java 에서이 문제를 해결하는 방법을 모르겠습니다. 데이터 블로 브의 유형이 이기종이기 때문에 (예 : 타임 스탬프 + 목록 또는 문자열 + 목록 …) 중간 클래스를 사전으로 대체하여 중간 클래스를 억제 할 수 없습니다. 컨테이너 클래스를 필드로 대체하는 대안 (예 : “m_epoch”변수를 “m_modules”로 전달)은 암시 적 객체 (다른 것없이 가질 수 없음)를 만들지 않기 때문에 매우 나쁩니다. 이익.

내 편견 언어 (Python)에서 내 규칙은 특정 논리 (기본 가져 오기 및 설정 제외)가 없으면 객체를 만들지 않는 것입니다. 그러나 제약 조건이 있다면, 당신이 가진 컴포지션 계층 구조가 가장 좋은 디자인이라고 생각합니다.


답변