当唯一的区别是一个变量的类型时重构重复的代码?
我必须能够连接到两个不同版本的 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
}
}
请注意,我必须有两个不同的连接器,因为一个方法调用(out数百)API 上在 1.5 中有一个新参数。
Foo14WebReference.customerEntity 和 Foo15WebReference.customerEntity 两个类具有相同的属性。
I have to be able to connect to two different versions of the an API (1.4 and 1.5), lets call it the Foo API. And my code that connects to the API and processes the results is substantially duplicated - the only difference is the data types returned from the two APIs. How can I refactor this to remove duplication?
In Foo14Connector.cs (my own class that calls the 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
}
}
And in the almost exact duplicate class Foo15Connector.cs (my own class that calls the 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
}
}
Note that I have to have two different connectors because one single method call (out of hundreds) on the API has a new parameter in 1.5.
Both classes Foo14WebReference.customerEntity and Foo15WebReference.customerEntity have identical properties.
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(3)
如果连接器位于不同的项目中,则这是一个很容易解决的情况:
添加一个新的类文件,将其命名为 ConnectorCommon 并复制所有公共代码,但删除命名空间。使此类成为分部类,并将该类(而不是文件)重命名为类似 Connector 的名称。
您需要为每个项目添加一个链接。
接下来,从当前连接器类中删除所有代码,将类(不一定是文件)重命名为与分部类相同的名称,并添加引用命名空间的 using 语句。
这应该得到你正在寻找的东西。
因此,完成后您将拥有:
File ConnectorCommon:
File Magento15Connector
File Magento14Connector
更新
这个过程一开始可能会有点混乱。
澄清一下,您正在两个项目之间的公共文件中共享源代码。
实际的类是每个项目中具有名称空间的特定类。您可以使用partial 关键字使公共文件与每个项目中的实际项目文件(即Magneto14)相结合,以便在编译时在该项目中创建完整的类。
最棘手的部分是将公共文件添加到两个项目中。
为此,请在第二个项目中选择“添加现有项目...”菜单,导航到公共文件,然后单击“添加”按钮旁边的右箭头。
从下拉菜单中,选择
添加为链接
。这会将文件的引用添加到第二个项目。源代码将包含在两个项目中,并且对公共文件的任何更改都将自动在两个项目中可用。更新 2
我有时会忘记 VB 使这样的任务是多么容易,因为那是我普通的编程环境。
为了在 C# 中实现此功能,还必须使用一个技巧:
条件编译符号
。它使通用代码的开头比我想要的更冗长,但它仍然确保您可以使用一组通用代码。要使用此技巧,请向每个项目添加一个条件编译符号(确保为
所有配置
设置它)。例如,在Magento14
项目中添加Ver14
,在Magento15
项目中添加Ver15
。然后在公共文件中,将命名空间替换为类似于以下的结构:
这将确保根据公共代码编译到的项目包含正确的命名空间和用法。
请注意,所有常见的
using
语句都应保留在公共文件中(即足以使其编译)。If the connectors are in different projects, this is an easy situation to solve:
Add a new class file, call it ConnectorCommon and copy all of the common code, but with the namespaces removed. Make this class a partial class and rename the class (not the file) to something like Connector.
You will need to add a link to this to each project.
Next, remove all of the code from your current connector classes, rename the class (not necessarily the file) to the same as the partial class, and add a using statement that references the namespace.
This should get what you are looking for.
So, when you are done you will have:
File ConnectorCommon:
File Magento15Connector
File Magento14Connector
Update
This process can be a little confusing at first.
To clarify, you are sharing source code in a common file between two projects.
The actual classes are the specific classes with the namespaces in each project. You use the partial keyword to cause the common file to be combined with the actual project file (i.e. Magneto14) in each project to create the full class within that project at compile time.
The trickiest part is adding the common file to both projects.
To do this, select the
Add Existing Item...
menu in the second project, navigate to the common file and click the right-arrow next to theAdd
button.From the dropdown menu, select
Add as link
. This will add a reference to the file to the second project. The source code will be included in both projects and any changes to the common file will be automatically available in both projects.Update 2
I sometimes forget how easy VB makes tasks like this, since that is my ordinary programming environment.
In order to make this work in C#, there is one more trick that has to be employed:
Conditional compilation symbols
. It makes the start of the common code a little more verbose than I would like, but it still ensures that you can work with a single set of common code.To employ this trick, add a conditional compilation symbol to each project (ensure that it is set for
All Configurations
). For example, in theMagento14
project, addVer14
and in theMagento15
project addVer15
.Then in the common file, replace the namespace with a structure similar to the following:
This will ensure that the proper namespace and usings are included based on the project the common code is being compiled into.
Note that all common
using
statements should be retained in the common file (i.e., enough to get it to compile).如果 FooConnectors 未密封并且您可以控制创建新实例,那么您可以派生自己的连接器并同时实现接口。在 C# 中,您可以通过简单地从基类继承成员来实现成员!
进而
If the FooConnectors are not sealed and you are in control to create new instances, then you can derive your own connectors and implement interfaces at the same time. In c# you can implement members by simply inheriting them from a base class!
and then
您应该引入两个实现通用的接口。如果项目是用相同的语言编写的并且位于不同的项目中,则可以引入两个项目引用的公共项目。然后,您将朝着仅依赖于接口的方向发展,这应该允许您使用控制反转(谷歌、依赖注入或服务定位器或工厂模式)在幕后的某个地方交换不同的实现。
您面临的困难可能是:
1)实现中的公共静态方法无法通过接口静态公开
2) 一个实现类(即 Foo14Connector 或 Foo15Connector)中可能存在将代码放入通用接口中没有意义的代码
You should introduce an interface that is common to both of the implementations. If the projects are written in the same language and are in different projects, you can introduce a common project that both projects reference. You are then making a move towards having dependencies only on your interface which should allow you to swap in different implementations behind the scenes somewhere using inversion of control (google, dependency injection or service locator or factory pattern).
Difficulties for you could be:
1) Public static methods in the implementations are not able to be exposed staticly via an interface
2) Potentially have code in one implementation class ie Foo14Connector or Foo15Connector that doesnt make sense to put into a generic interface