我的目标是向客户端隐藏我正在构建的类的所有细节,包括要实例化的具体类。
客户端将枚举传递给一个工厂,该工厂返回相应派生类的实例,如下所示:
IAutomobile auto = Autofactory.GetAuto(param);我创建了一个基类来完成大部分工作,但我需要特定的派生类来实现特定的逻辑。
public interface IAutomobile
{
void Rename(string p1, int p2);
}
public abstract class Automobile : IAutomobile
{
// Lots of properties and methods...
public abstract void Rename(string p1, int p2);
}
public class Jeep : Automobile
{
public override void Rename(string p1, int p2)
{
// Uses p1 & p2 with the base class
}
}现在,客户端可以调用:
auto.Rename("s1", "s2");当然,在我创建另一个派生类以不同的签名实现"Rename()“方法之前,一切都很好。
public class Audi : Automobile
{
public override void Rename(int i, SomeOtherClass someOtherClass)
{
//Does something with params
}
}第二个实现有一个不同的签名,这并不令人意外地抛出编译错误。
因此,通过使用这样的字典,我试图使传递的参数更加“灵活”:
public interface IAutomobile
{
void Rename(Dictionary<object, object> parameters);
}客户端:
public class client
{
public void Client()
{
var parameters = new Dictionary<object, object>();
IAutomobile auto = AutoFactory.GetFactory();
parameters.Add("Param1Name", "string1");
parameters.Add("Param2Name", 21);
auto.Rename(parameters);
}
}派生类:
public class Audi : Automobile, IAutomobile
{
public override void Rename(Dictionary<object, object> parameters)
{
// cast/box/unbox from dictionary objects...
// does something unique for Audis...
}
} 所以,我就是这样用字典实现的,其中参数是键/值对,但这似乎是糟糕的。我不明白它怎么会给我买任何东西。
或者,我可以创建一个对象,它表示所有派生类参数的联合,但同样,这看起来很糟糕。
有人能建议我如何安排这件事,这样就不需要演员、拳击和非拳击了?
我不介意公开与Rename()方法一起使用的对象,例如:
auto.Rename(AudiFeatures);或
auto.Rename(JeepFeatures);(顺便说一句,我真的不想传递单个的对角线,我想传递对象)
这样的客户端调用将无法工作,因为我必须对客户端代码中的类型进行硬编码。我想在工厂中对其进行硬编码,但是如何返回正确的接口类型,以及工厂的返回类型是什么?
我不想这么做:
IAutomobile<JeepRenamingData> auto = Autofactory.GetAuto<JeepRenamingData>(param);我想这么做:
IAutomobile auto = Autofactory.GetAuto(param);
auto.Rename(myJeepRenamingData);并让工厂返回正确的类型:
public static IAuto GetAutomobileManager(AutoMaker manufacturer)
{
switch (manufacturer)
{
case AutoMaker.Jeep
return new Jeep<JeepNamingOptions>();
case AutoMaker.Audi
return new Audi<AudiNamingOptions>();
}
}发布于 2016-12-23 00:06:58
最直接的想法是使用泛型。你能做到吗?
public interface IAutomobile { }
public interface IAutomobile<P1, P2> : IAutomobile
{
void Rename(P1 p1, P2 p2);
}
public abstract class Automobile<P1, P2> : IAutomobile<P1, P2>
{
// Lots of properties and methods...
public abstract void Rename(P1 p1, P2 p2);
}
public class Jeep : Automobile<string, int>
{
public override void Rename(string p1, int p2)
{
// Uses p1 & p2 with the base class
}
}然后,客户端调用将如下所示:
IAutomobile<string, int> auto = Autofactory.GetAuto<string, int>(param);
auto.Rename("Foo", 42);
IAutomobile auto_plain = auto;根据你的最新情况,这是我现在的建议:
IAutomobile<JeepFeatures> auto = Autofactory.GetAuto<JeepFeatures>(param);
auto.Rename(new JeepFeatures());
IAutomobile auto_plain = auto;
public interface IAutomobile { }
public interface IAutomobile<P> : IAutomobile
{
void Rename(P parameters);
}
public abstract class Automobile<P> : IAutomobile<P>
{
public abstract void Rename(P parameters);
}
public class Jeep : Automobile<JeepFeatures>
{
public override void Rename(JeepFeatures parameters)
{
}
}发布于 2016-12-23 10:52:01
对我来说,无论哪种方式,您当前的方法都存在设计缺陷。
虽然你想要完全隐藏混凝土汽车的细节,你需要具体的细节,因为你不能工作的汽车,你根本不知道.总之,--我看到了过多的抽象。
不需要像IAutomobile这样过于抽象的接口来操纵您的汽车,您应该使用接口的强大功能从头开始解决您的问题:
public interface ICanRename<TArgs>
where TArgs : class
{
void Rename(TArgs args);
}
public interface IAutomobile
{
// Other common behaviors
}
public interface IJeep : IAutomobile, ICanRename<JeepRenameArgs>
{
}
public class JeepRenameArgs {}
public class Jeep: IJeep
{
public void Rename(JeepRenameArgs args)
{
// Rename stuff
}
}
public class AutomobileFactory
{
private Dictionary<Type, Type> AutomobileImplementations = new Dictionary<Type, Type>
{
{ typeof(IJeep), typeof(Jeep) }
};
public TAutomobile Create<TAutomobile>()
where TAutomobile : IAutomobile
{
TAutomobile automobile = (TAutomobile)Activator.CreateInstance(AutomobileImplementations[typeof(TAutomobile)]);
// Some initialization stuff here
return automobile;
}
}因此,您可以获得如下的汽车实现:
AutomobileFactory automobileFactory = new AutomobileFactory();
IJeep jeep = automobileFactory.Create<IJeep>();
jeep.Rename(new JeepRenameArgs());
// or even:
ICanRename<JeepRenameArgs> jeep2 = automobileFactory.Create<IJeep>() as ICanRename<JeepRenameArgs>;
jeep2.Rename(new JeepRenameArgs());看看如何在不知道实现或接口的情况下重命名一个Jeep!
不管怎样..。
看来你最终会重新发明方向盘。上面的代码,甚至是您的代码,似乎是控制容器服务定位器的基本反转。
使用像http://www.castleproject.org/这样的东西怎么样?
WindsorContainer container = new WindsorContainer();
container.Register
(
Classes.FromThisAssembly().BasedOn<IAutomobile>()
.WithServiceAllInterfaces().LifestyleTransient()
);
IJeep jeep = container.Resolve<IJeep>();或者,为了不走向邪恶(你应该避免服务定位器反模式),你应该利用依赖注入
public class YourClass
{
public YourClass(IJeep jeep)
{
Jeep = jeep;
}
private IJeep Jeep { get; }
public void DoStuff()
{
Jeep.Rename(new JeepArgs());
}
}...and让反转控制容器为您注入所需的汽车实现!
https://stackoverflow.com/questions/41293399
复制相似问题