我必须能够连接两个不同版本的API(1.4和1.5),我们称之为Foo API。我连接到API并处理结果的代码基本上是重复的 - 唯一的区别是从两个API返回的数据类型。我怎样才能重构这个以消除重复?
在Foo14Connector.cs(我自己的类中调用1.4 API)
public class Foo14Connector
{
public void GetAllCustomers()
{
var _foo = new Foo14WebReference.FooService();
Foo14WebReference.customerEntity[] customers = _foo.getCustomerList;
foreach (Foo14WebReference.customerEntity customer in customers)
{
GetSingleCustomer(customer);
}
}
public void GetSingleCustomer(Foo14WebReference.customerEntity customer)
{
var id = customer.foo_id;
// etc
}
}
在几乎完全重复的类Foo15Connector.cs(我自己的类调用1.5 API)中
public class Foo15Connector
{
public void GetAllCustomers()
{
var _foo = new Foo15WebReference.FooService();
Foo15WebReference.customerEntity[] customers = _foo.getCustomerList;
foreach (Foo15WebReference.customerEntity customer in customers)
{
GetSingleCustomer(customer);
}
}
public void GetSingleCustomer(Foo15WebReference.customerEntity customer)
{
var id = customer.foo_id;
// etc
}
}
请注意,我必须有两个不同的连接器,因为API上的一个方法调用(数百个)在1.5中有一个新参数。
两个类Foo14WebReference.customerEntity和Foo15WebReference.customerEntity都具有相同的属性。
答案 0 :(得分:5)
如果连接器位于不同的项目中,这很容易解决:
添加一个新的类文件,将其称为ConnectorCommon并复制所有公共代码,但删除了名称空间。将此类设为部分类,并将类(而不是文件)重命名为Connector。
您需要为每个项目添加一个链接。
接下来,从当前连接器类中删除所有代码,将类(不一定是文件)重命名为与partial类相同,并添加引用命名空间的using语句。
这应该得到你想要的东西。
所以,当你完成后,你将拥有:
文件ConnectorCommon:
public partial class Connector
{
public void GetAllCustomers()
{
var _foo = new FooService();
customerEntity[] customers = _foo.getCustomerList;
foreach (customerEntity customer in customers)
{
GetSingleCustomer(customer);
}
}
public void GetSingleCustomer(customerEntity customer)
{
var id = customer.foo_id;
// etc
}
}
文件Magento15Connector
using Foo15WebReference;
partial class Connector
{
}
文件Magento14Connector
using Foo14WebReference;
partial class Connector
{
}
<强>更新强>
这个过程起初可能有点令人困惑。
为了澄清,您将在两个项目之间的共同文件中共享源代码。
实际的类是每个项目中具有命名空间的特定类。您可以使用partial关键字将公共文件与每个项目中的实际项目文件(即Magneto14)组合在一起,以便在编译时在该项目中创建完整的类。
最棘手的部分是将公共文件添加到两个项目中。
要执行此操作,请在第二个项目中选择Add Existing Item...
菜单,导航到公共文件,然后单击Add
按钮旁边的右箭头。
从下拉菜单中选择Add as link
。这会将引用添加到第二个项目的文件中。源代码将包含在两个项目中,对公共文件的任何更改都将在两个项目中自动提供。
更新2
我有时会忘记VB如何轻松地完成这样的任务,因为这是我普通的编程环境。
为了在C#中完成这项工作,还有一个必须采用的技巧:Conditional compilation symbols
。它使公共代码的开始比我想要的更冗长,但它仍然确保你可以使用一组公共代码。
要使用此技巧,请为每个项目添加条件编译符号(确保为All Configurations
设置)。例如,在Magento14
项目中,添加Ver14
并在Magento15
项目中添加Ver15
。
然后在公共文件中,使用类似于以下内容的结构替换命名空间:
#if Ver14
using Magneto14;
namespace Magento14Project
#elif Ver15
using Magneto15;
namespace Magento15Project
#endif
这将确保根据编译公共代码的项目包含正确的命名空间和用法。
请注意,所有常见using
语句都应保留在公共文件中(即足以使其编译)。
答案 1 :(得分:1)
如果FooConnectors没有密封并且您可以控制创建新实例,那么您可以同时派生自己的连接器并实现接口。在c#中,您可以通过简单地从基类继承它们来实现成员!
public IFooConnector {
void GetAllCustomers();
}
public MyFoo14Connector : Foo14Connector, IFooConnector
{
// No need to put any code in here!
}
然后
IFooConnector connector = new MyFoo14Connector();
connector.GetAllCustomers();
答案 2 :(得分:0)
您应该引入两个实现共有的接口。如果项目使用相同的语言编写并且位于不同的项目中,则可以引入两个项目都引用的公共项目。然后,您将转向仅依赖于您的接口,这应该允许您使用控制反转(谷歌,依赖注入或服务定位器或工厂模式)在幕后交换不同的实现。
您的困难可能是:
1)实现中的公共静态方法无法通过接口静态公开 2)在一个实现类中可能有代码,即Foo14Connector或Foo15Connector,它们没有意义放入通用接口