当唯一的区别是一个变量的类型时重构重复的代码?

发布于 2024-12-25 02:56:28 字数 1391 浏览 2 评论 0原文

我必须能够连接到两个不同版本的 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 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(3

时光暖心i 2025-01-01 02:56:28

如果连接器位于不同的项目中,则这是一个很容易解决的情况:

添加一个新的类文件,将其命名为 ConnectorCommon 并复制所有公共代码,但删除命名空间。使此类成为分部类,并将该类(而不是文件)重命名为类似 Connector 的名称。

您需要为每个项目添加一个链接。

接下来,从当前连接器类中删除所有代码,将类(不一定是文件)重命名为与分部类相同的名称,并添加引用命名空间的 using 语句。

这应该得到你正在寻找的东西。

因此,完成后您将拥有:

File 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 
    }
}

File Magento15Connector

using Foo15WebReference;

partial class Connector
{
}

File Magento14Connector

using Foo14WebReference;

partial class Connector
{
}

更新

这个过程一开始可能会有点混乱。

澄清一下,您正在两个项目之间的公共文件中共享源代码

实际的类是每个项目中具有名称空间的特定类。您可以使用partial 关键字使公共文件与每个项目中的实际项目文件(即Magneto14)相结合,以便在编译时在该项目中创建完整的类。

最棘手的部分是将公共文件添加到两个项目中。

为此,请在第二个项目中选择“添加现有项目...”菜单,导航到公共文件,然后单击“添加”按钮旁边的右箭头。

从下拉菜单中,选择添加为链接。这会将文件的引用添加到第二个项目。源代码将包含在两个项目中,并且对公共文件的任何更改都将自动在两个项目中可用。

更新 2

我有时会忘记 VB 使这样的任务是多么容易,因为那是我普通的编程环境。

为了在 C# 中实现此功能,还必须使用一个技巧:条件编译符号。它使通用代码的开头比我想要的更冗长,但它仍然确保您可以使用一组通用代码。

要使用此技巧,请向每个项目添加一个条件编译符号(确保为所有配置设置它)。例如,在 Magento14 项目中添加 Ver14,在 Magento15 项目中添加 Ver15

然后在公共文件中,将命名空间替换为类似于以下的结构:

#if Ver14
using Magneto14;
namespace Magento14Project

#elif Ver15
using Magneto15;
namespace Magento15Project

#endif

这将确保根据公共代码编译到的项目包含正确的命名空间和用法。

请注意,所有常见的 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:

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 
    }
}

File Magento15Connector

using Foo15WebReference;

partial class Connector
{
}

File Magento14Connector

using Foo14WebReference;

partial class Connector
{
}

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 the Add 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 the Magento14 project, add Ver14 and in the Magento15 project add Ver15.

Then in the common file, replace the namespace with a structure similar to the following:

#if Ver14
using Magneto14;
namespace Magento14Project

#elif Ver15
using Magneto15;
namespace Magento15Project

#endif

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).

情栀口红 2025-01-01 02:56:28

如果 FooConnectors 未密封并且您可以控制创建新实例,那么您可以派生自己的连接器并同时实现接口。在 C# 中,您可以通过简单地从基类继承成员来实现成员!

public IFooConnector {
    void GetAllCustomers();
}

public MyFoo14Connector : Foo14Connector, IFooConnector
{
    // No need to put any code in here!
}

进而

IFooConnector connector = new MyFoo14Connector();
connector.GetAllCustomers();

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!

public IFooConnector {
    void GetAllCustomers();
}

public MyFoo14Connector : Foo14Connector, IFooConnector
{
    // No need to put any code in here!
}

and then

IFooConnector connector = new MyFoo14Connector();
connector.GetAllCustomers();
尴尬癌患者 2025-01-01 02:56:28

您应该引入两个实现通用的接口。如果项目是用相同的语言编写的并且位于不同的项目中,则可以引入两个项目引用的公共项目。然后,您将朝着仅依赖于接口的方向发展,这应该允许您使用控制反转(谷歌、依赖注入或服务定位器或工厂模式)在幕后的某个地方交换不同的实现。

您面临的困难可能是:

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

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文