我迷失了,需要一些神圣的指导。
首先要做的事情:假设你有一些很好的接口:
class IProduct
{
public:
virtual void DoThings();
}
enum ProductType
{
...
}
class IProducer
{
public:
virtual IProduct* Produce( ProductType type );
}
class IConsumer
{
public:
virtual void Consume( IProduct* product );
}
简单明了:抽象工厂,抽象消费者将调用界面,很快由那些新生成的IP产品提供。 但这里有棘手的部分。 假设有两个(或更多)并行混凝土组:
class ConcreteProducerA : public IProducer { ... }
class ConcreteConsumerA : public IConsumer { ... }
class ConcreteProductA : public IProduct { ... }
class ConcreteProducerB : public IProducer { ... }
class ConcreteConsumerB : public IConsumer { ... }
class ConcreteProductB : public IProduct { ... }
那些混凝土是不同的东西。就像航天飞机零件(零件工厂和梭子装配线)和蔬菜袋(带有农场和...... idk,谁会吃这些蔬菜?)。然而他们总体上有这样的事情:DoThings()。无论你喜欢什么,假装它是PackAndSend(),Serialize()或Dispose()。没有什么具体的,但基于层次结构的合法性。 但那些仍然比一般性更多的差异。所以那些ConcreteConsumers倾向于以不同的方式使用它们。事实上,他们绝对必须确定,这应该是具体的类型。
所以这就是问题所在:我正在强迫该层次结构的用户立即将IPoduct转发到他们的虚拟覆盖中的ConcreteProduct。这让我很烦恼。我觉得我错过了一些东西:层次结构中的一个大缺陷,一些缺乏模式知识,一些东西。 我的意思是,我可以确定,ConcreteConsumerB总是收到ConcreteProductB,但它仍然是一个垂头丧气。你会不会使用一个框架,它总是绕过(void *)并迫使你把它投射到你认为会来的时候?
我已经考虑过的解决方案:
(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 );
}
}
通过这种方式,我可以控制那个沮丧的人,但现在已经存在了。
无论如何,这个问题对某人来说听起来很熟悉吗?有人看到它解决了,或者可能是英雄式的解决了吗? C ++解决方案很棒,但我认为任何静态类型的语言都足够了。
答案 0 :(得分:2)
一种可能性是将第二层引入热层次结构。从IShuttle
获取IProduct
,并从中派生该组。然后添加IShuttleProducer
,产生IShuttle*
而不是IProduct*
。这没关系,因为C ++允许虚函数的协变返回类型......只要新的返回类型派生自原始类型,它仍然被认为是覆盖。
但是你的设计可能需要重新思考。
答案 1 :(得分:2)
然而他们总体上有这样的事情:DoThings()。假装它是, 比如,PackAndSend(),或Serialize(),或Dispose(),无论你喜欢什么。 没有什么具体的,但基于层次结构的合法性。
仅仅因为他们可以处于某种层次结构中,并不意味着他们应该这样做。他们是无关的。通过推广航天飞机和蔬菜,我甚至无法理解你在任何代码库中增加的价值。如果它不会给用户带来好处,那么你可能只会让事情变得更加复杂。
我希望看到如下界面。请注意,他们不会继承任何东西。如果您有共享代码,请编写更简单的哑混凝土类,人们可以通过合成重用它们。
template<typename T>
class Producer {
public:
virtual ~Producer() {}
virtual std::auto_ptr<T> produce() = 0;
};
template<typename T>
class Consumer {
public:
virtual ~Consumer() {}
virtual void consume(std::auto_ptr<T> val) = 0;
};
然后我希望看到从各种来源创建这些功能的具体功能。
typedef Producer<Shuttle> ShuttleProducer;
typedef Consumer<Shuttle> ShuttleConsumer;
std::auto_ptr<ShuttleProducer> GetShuttleProducerFromFile(...);
std::auto_ptr<ShuttleProducer> GetShuttleProducerFromTheWeb(...);
std::auto_ptr<ShuttleProducer> GetDefaultShuttleProducer();
可能没有你想要做的模式,你可能会将两种模式(技术术语)放在一起。你没有背叛为什么这些东西应该共享一个代码库,所以我们只能猜测。
在更复杂的场景中,您需要严格区分使用和创建。将不同的界面看起来很相似,但使用方式不同,这是完全有效的。
class Foo {
public:
virtual ~Foo() {}
virtual void doStuff() = 0;
virtual void metamorphose() = 0;
};
class Fu {
public:
virtual ~Fu() {}
virtual void doStuff() = 0;
virtual void transmorgrify() = 0;
};