객체가 소유자를 많이 알고 있으면 코드 냄새가 나는가?


9

Delphi 2007 응용 프로그램에서 우리는 다음과 같은 많은 구성을 사용하고 있습니다

FdmBasic:=TdmBasicData(FindOwnerClass(AOwner,TdmBasicData));

FindOwnerClass는 현재 구성 요소의 소유자 계층 구조를 위로 이동하여 특정 클래스 (예 : TdmBasicData)를 찾습니다. 결과 객체는 필드 변수 FdmBasic에 저장됩니다. 우리는 주로 데이터 모듈을 전달하는 데 사용합니다.

예 : 보고서를 생성 할 때 결과 데이터는 압축되어 TdmReportBaseData 데이터 모듈을 통해 액세스 된 테이블의 Blob 필드에 저장됩니다. 응용 프로그램의 별도 모듈에는 ReportBuilder를 사용하여 보고서의 데이터를 페이지 형식으로 표시하는 기능이 있습니다. 이 모듈의 기본 코드 (TdmRBReport)는 클래스 TRBTempdatabase를 사용하여 압축 된 BLOB 데이터를 Reportbuilder 런타임 보고서 디자이너에서 사용할 수있는 다른 테이블로 변환합니다. TdmRBReport는 모든 종류의 보고서 관련 데이터 (보고서 유형, 보고서 계산 설정 등)에 대해 TdmReportBaseData에 액세스 할 수 있습니다. TRBTempDatabase는 TdmRBReport로 구성되지만 TdmReportBasedata에 액세스해야합니다. 이제 이것은 위의 구성을 사용하여 수행됩니다.

constructor TRBTempDatabase.Create(aOwner: TComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(FindOwnerClass(Owner, TdmRBReport)).dmReportBaseData;
end;{- .Create }

내 생각에 이것은 TRBTempDatabase가 많은 소유자를 알고 있다는 것을 의미하며 이것이 일종의 코드 냄새인지 안티 패턴인지 궁금합니다.

이것에 대한 당신의 생각은 무엇입니까? 이것이 코드 냄새입니까? 그렇다면 더 좋은 방법은 무엇입니까?


1
다른 수업에 대해 많이 알고 있어야한다면 더 쉬운 방법이 제공되었을 것입니다.
Loren Pechtel

답변:


13

이런 종류는 Martin Fowler (일반적인 안티 패턴으로 식별 된)에 의해 처음 설명 된 Service Locator 패턴과 비슷합니다.

건설 기반 의존성 주입은 요구 매개 변수의 가시성을 높이고 더 간단한 단위 테스트를 촉진하므로 서비스 로케이터보다 선호됩니다.

서비스 로케이터 사용의 문제점은 특정 서비스 로케이터 구현에 대한 종속성을 취하지는 않지만 (문제가 될 수도 있지만) 선의의 안티 패턴입니다. 그것은 API 소비자에게 끔찍한 개발자 경험을 제공 할 것이며, 모든 변경의 의미를 파악하기 위해 상당한 양의 두뇌 능력을 사용해야하기 때문에 유지 보수 개발자로서의 삶을 악화시킬 것입니다.

컴파일러는 생성자 주입을 사용할 때 소비자와 생산자 모두에게 많은 도움을 제공 할 수 있지만 Service Locator에 의존하는 API에는 이러한 지원이 제공되지 않습니다.

또한 가장 주목할만한 점은 데메테르 법칙을 어기는 것입니다

LoD (Law of Demeter) 또는 Least Knowledge의 원리는 소프트웨어, 특히 객체 지향 프로그램을 개발하기위한 설계 지침입니다. 일반적으로 LoD는 느슨한 결합의 경우입니다.

함수에 대한 Demeter of Law는 객체 O의 메소드 M이 다음과 같은 객체의 메소드 만 호출 할 수 있어야합니다.

  1. O 자체
  2. M의 매개 변수
  3. M 내에서 생성 / 인스턴스화 된 객체
  4. O의 직접 컴포넌트 객체
  5. M의 범위에서 O에 의해 액세스 가능한 전역 변수

특히 객체는 다른 메서드에서 반환 한 멤버 객체의 메서드를 호출하지 않아야합니다. 점을 필드 식별자로 사용하는 많은 현대 객체 지향 언어의 경우, 법은 간단히 "하나의 점만 사용"으로 표시 할 수 있습니다. 즉, 코드 abMethod ()는 a.Method ()가하지 않는 법칙을 위반합니다. 간단한 예로, 개를 산책하고 싶을 때 개 다리를 직접 걷도록 명령하는 것은 어리석은 일입니다. 대신 하나는 개를 명령하고 자신의 다리를 돌보게합니다.

더 나은 방법

효과적으로 더 좋은 방법은 클래스 내에서 서비스 로케이터 호출을 제거하고 올바른 소유자를 생성자 내부의 매개 변수로 전달하는 것입니다. 이것이 소유자를 조회하고 클래스 생성자에게 전달하는 서비스 클래스가 있음을 의미하더라도

constructor TRBTempDatabase.Create(aOwner: TComponent, ownerClass: IComponent);
begin
  inherited Create(aOwner);

  FdmReportBaseData := TdmRBReport(ownerClass).dmReportBaseData;
end;{- .Create }

3
훌륭한 답변과이 훌륭한 비유를 생각 해낸 사람에게 소품 :As a simple example, when one wants to walk a dog, it would be folly to command the dog's legs to walk directly; instead one commands the dog and lets it take care of its own legs.
Andy Hunt

3

자식 개체가 부모에 대해 너무 많이 알고있는 데 따른 어려움 중 하나는 너무 밀접하게 연결될 수있는 패턴을 구현하게되어 결국 큰 의존성 두통이 발생하고 나중에 안전하게 수정하고 유지하기가 매우 어렵다는 것입니다 나중에.

두 클래스가 얼마나 깊이 연결되어 있는지에 따라 Fowler의 Feature Envy 또는 부적절한 친밀감 코드 냄새에 대한 설명과 비슷합니다.

데이터가있는 클래스를로드하거나 읽어야하는 것으로 보이며,이 경우 여러 대체 패턴을 사용하여 자식과 부모 체인 간의 종속성을 깰 수 있으며 액세스 작업을 위임해야하는 것처럼 들립니다. 데이터 접근 자 클래스가 모든 것을 스스로 수행하도록하는 대신 데이터 클래스.

당사 사이트를 사용함과 동시에 당사의 쿠키 정책개인정보 보호정책을 읽고 이해하였음을 인정하는 것으로 간주합니다.
Licensed under cc by-sa 3.0 with attribution required.