我有2个不同的第三方程序集,它们为业务服务提供相同的API并使用相同的类名(~40个类/类型/扩展名)但位于不同的程序集中:
Company.Assemply.V1
Company.Assemply.V2
我在项目中引用了两个程序集。
这些程序集没有通用接口,第三方无法提供通用接口
因此,c#编译器将两个程序集中的每个类型视为不同的类型。
我想为每个程序集实现一个类Myservice
以支持两个版本V1 / V2。
我使用以下代码来实现Myservice.V1.Myclass
//#define V1
#if V1
using Company.Assemply.V1;
#else
using Company.Assemply.V2;
#endif
#if V1
namespace Myservice.V1
#else
namespace Myservice.V2
#endif
{
//my implementation that use all classes /types in any v1/v2 assembly
class MyClass {.... }
}
然后我将相同的代码复制并粘贴到其他c#文件MyClassV2.cs
(大约400行)中以获取Myservice.V2.Myclass
并取消注释编译器标记#define V1
我不能使用泛型
MyClass <T> where T:??
因为T
没有通用接口这两个班级工作正常。
问题是在维护v1时,我必须将代码复制/粘贴到另一个文件MyClassV2.cs
中,并取消注释编译器标志#define V1
以支持V2。
是否有更好的方法/合适的设计模式/重构技术可以解决这样的问题。 我想使用/维护一个代码库,避免复制/粘贴其他类版本。
给我一个重构上述代码的例子。
答案 0 :(得分:5)
一种选择是使用adapter pattern,这是向BCL和不使用它们的第三方代码添加抽象的常用方法。例如,您在名为MyClass
的第三方程序集中有一个类型,V1
和V2
共享相同的成员:
public interface IMyClass
{
// All members of MyClass
// (except we have a special case for DoSomething() because it
// has a return type SomeType we also need to adapt to ISomeType).
ISomeType DoSomething();
}
public class MyClassV1 : V1.MyClass, IMyClass
{
// No need to re-implement members (base class satisfies interface)
// However, if there are return parameters, you will need to
// also use a decorator pattern to wrap them in another adapter.
public override ISomeType DoSomething()
{
return new SomeTypeV1(base.DoSomething());
}
}
public class MyClassV2 : V2.MyClass, IMyClass
{
}
public interface ISomeType
{
// All members of SomeType
}
public class SomeTypeV1 : ISomeType
{
private readonly SomeType someType;
public SomeType(SomeType someType)
{
this.someType = someType;
}
// re-implement all members and cascade the call to someType
}
然后您可以在您的应用程序中使用IMyClass
,使用DI注入您需要的任何一个。
public class HomeController : Controller
{
private readonly IMyClass myClass;
public HomeController(IMyClass myClass)
{
this.myClass = myClass
}
}
如果您需要在运行时在实现之间切换,请考虑strategy pattern。