나는 잃어버린 일부 신성한 지침이 필요합니다.abstact hierarcy의 구체적인 인스턴스에 대한 계약 시행
중요한 것부터 먼저 : 당신은 몇 가지 잘-깔끔한 인터페이스를 가지고 가정
class IProduct
{
public:
virtual void DoThings();
}
enum ProductType
{
...
}
class IProducer
{
public:
virtual IProduct* Produce(ProductType type);
}
class IConsumer
{
public:
virtual void Consume(IProduct* product);
}
그것의 일반 간단하면서도 : 추상적 인 공장, 기꺼이 그 갓 산란 IProducts에서 제공하는 인터페이스를 호출합니다 추상적 인 소비자. 하지만 여기 까다로운 부분이 있습니다. 가 두 개 (또는 그 이상)의 병렬 콘크리트 그룹입니다한다고 가정
class ConcreteProducerA : public IProducer { ... }
class ConcreteConsumerA : public IConsumer { ... }
class ConcreteProductA : public IProduct { ... }
class ConcreteProducerB : public IProducer { ... }
class ConcreteConsumerB : public IConsumer { ... }
class ConcreteProductB : public IProduct { ... }
그리고 그 콘크리트가 reeealy 다른 것입니다. 우주 왕복선 부품 (부품 공장과 셔틀 조립 라인이 있음)과 야채 봉지 (농장과 .. idk와 함께 누가 그 야채를 소비합니까?)처럼. 그러나 그들은 DoThings()과 같은 일반적인 것을 가지고 있습니다. 원하는대로 PackAndSend(), Serialize() 또는 Dispose()와 같은 척하십시오. 구체적인 것은 아니지만 계층을 기반으로하는 합법적 인 것입니다. 그러나 그것들은 일반성보다 더 많은 차이점을 가지고 있습니다. 그래서 그 ConcreteConsumers는 다르게 그들을 사용하는 경향이 있습니다. 그래서 다르게, 실제로, 그들은 절대적으로 확실해야합니다, 그것은 콘크리트 타입이라고 가정합니다.
그래서 여기에 문제가 있습니다 : 나는 그 계층의 사용자가 지금 IPoduct를 그들의 가상 오버라이드에서 ConcreteProduct로 다운 캐스트하도록하고 있습니다. 그리고 저를 괴롭히는 것이 어렵습니다. 나는 내가 무언가를 놓치고 있다고 느낍니다 : 계급의 큰 결함, 패턴 지식의 부족, 무언가. 제 말은 ConcreteConsumerB가 항상 ConcreteProductB를 수신한다는 것을 확인할 수 있습니다.하지만 여전히 다운 캐스트입니다. 그리고 당신은 언제나 (void *)의 주위를 돌아 다니며, 나중에 올 것이라고 생각할 때 그것을 캐스팅하도록하는 프레임 워크를 사용했을 것입니까?
솔루션은 내가 이미 고려했습니다 i- 제품에
- 터널 모든 conctrete의 interfeces. 하지만 그 제품 gona는 Eat(), BeEaten(), Launch(), Destroy() 및 그 밖의 무엇을 알고있는 사람이 통제 할 수없는 얼룩으로 바뀝니다. 그래서이 해결책은 저를 배반하는 것보다 나은 것 같습니다.
- DoThings()은 IProduct에서 다른 핸들러로 분리 될 수 있습니다. 그러면 모든 Concret (Visitor-like)을 수용 할 수 있습니다. 그렇게하면 IProduct를 제거 할 수 있고 별도의 구체적인 그룹이 생깁니다. 하지만 SemiConcrete 레이어가 있으면 이러한 구체적인 그룹에 공통적 인 기능을 구현할 수 있습니까? 라벨링, 모핑, 마사지 등. 또한 다른 구체적인 그룹을 추가해야 할 경우 해당 방문자를 변경해야합니다.
(ab) 템플릿을 사용하십시오. 그것은 현재 현명 해 보인다.
의 라인을 따라 뭔가template < typename _IProduct > class IConcreteProducer : public IProducer { public: virtual _IProduct* Produce(_IProduct::Type type) = 0; virtual _IProduct::Type DeduceType(ProductType type) = 0; virtual IProduct* Produce(ProductType type) { return IConcreteProducer<typename _IProduct>::Produce(DeduceType(type)); } } template < typename _IProduct > class IConcreteConsumer : public IConsumer { public: virtual void Consume(_IProduct* product) = 0; virtual void Consume(IProduct* product) { IConcreteConsumer<typename _IProduct>::Consume((_IProduct*)product); } }
이 방법은 내가 다운 캐스트를 통제하고 있지만, 그것은 stil 선물입니다.
어쨌든이 문제는 누구에게 친숙합니까? 누군가 그것을 풀어 본 것입니까, 아니면 영웅적으로 해결 한 사람입니까? C++ 솔루션은 훌륭 하겠지만 통계적으로 형식화 된 언어이면 충분할 것입니다.
* "재주문이 다른 것"*이 상속 계층 구조이고 공장에서 실제 작업에 적합한 도구가 충분합니까? – Flexo
이것은 분명히 잘못되었습니다 :'IConcreteConsumer' –
Nawaz
@awoodland 우물쭈물은 다운 캐스트를 요구할 정도로 충분히 다르지만 최소한 코드를 재사용하기 위해서 (적어도 의미는 별개로) 공통 기반에서 파생되기에 충분합니다. Gracefuly를 파생어 (아직 OOP 스타일 유지)와 별도로 재사용 할 수있는 또 다른 방법이 있습니까? – Dark