创建一个支持随时间变化的工厂
本文关键字:时间 变化 工厂 支持 一个 创建 | 更新日期: 2023-09-27 18:36:38
我有一个引擎类,一个使用该引擎的应用程序类,以及一个抽象的接口 IEngine:
public interface IEngine
{
void Foo();
}
public class Engine1 : IEngine
{
public void Foo()
{
//...
}
}
public class App1
{
public void Do()
{
IEngine1 e = new Engine1();
e.Foo();
}
}
由于我可以有多个引擎,因此我正在实现一个引擎工厂,该工厂生产引擎并将它们返回为 IEngine:
public class EngineFactory
{
public IEngine CreateEngine(string engineName)
{
//returns the right engine according to 'engineName'
}
}
这样,App 和引擎是松散耦合的,任何 App 类都不会引用具体的引擎。
最后,我希望能够向(所有)引擎添加新方法。很自然的事情是将这些方法添加到 IEngine,但如果我要这样做,我将不得不重新编译所有使用 IEngine 的应用程序。我的解决方案是创建一个新的接口 IEngine2:
public interface IEngine2 : IEngine
{
void Goo();
}
但这将迫使我更改工厂中的 CreateEngine 方法签名。
我怎样才能避免这种情况?我应该将工厂更改为通用工厂吗?我应该使用 DI 吗?别的?
编辑:你可以这样想 - 我负责引擎实施,我的客户正在实施应用程序。现在有一个客户需要来自所有引擎的新功能,我需要实现该功能,而无需强制所有其他客户重新编译他们的应用程序(类似于 API 实现)。
解决方案可能是使用功能模式:
public interface IEngine
{
bool TryGetCapability<T>(out T capability);
}
public interface ICapability1
{
void Foo();
}
public class Engine1 : IEngine, ICapability1
{
public bool TryGetCapability<T>(out T capability)
{
if (this is T)
{
capability = this as T;
return true;
}
capability = default(T);
return false;
}
public void Foo()
{
//...
}
}
public class App1
{
public void Do()
{
IEngine e = new Engine1();
ICapability1 cap1;
if (e.TryGetCapability(out cap1))
{
cap1.Foo();
}
}
}
我使用引擎类来实现该功能,但在实际应用程序中,它通常会在每个功能的一个类上实现。
这是 COM 世界中的常见问题,一旦发布接口,就不应对其进行修改。COM 通常解决此问题的方法是使用从以前版本继承的新版本编号接口。
public interface IEngine
{
void Foo();
}
public interface IEngine2 : IEngine
{
void Goo();
}
public class EngineA : IEngine
{
public void Foo()
{
//...
}
}
public class EngineB : IEngine2
{
public void Foo()
{
//...
}
public void Goo()
{
//...
}
}
对于您的工厂,您可以让它始终返回 IEngine 或让它成为通用的,并且用户必须指定该项目必须支持的最小接口。
public class EngineFactory
{
public T CreateEngine<T>(string engineName) where T : IEngine
{
//returns the right engine according to 'engineName'
}
}
public class App
{
public void Do(EngineFactory factory)
{
//Creates a instance of EngineA
IEngine e = factory.CreateEngine<IEngine>("EngineA");
//returns a instance of EngineB
IEngine eB = factory.CreateEngine<IEngine>("EngineB");
//returns null
IEngine2 e2 = factory.CreateEngine<IEngine2>("EngineA");
//returns a instance of EngineB
IEngine2 e2B = factory.CreateEngine<IEngine2>("EngineB");
}
}