Рефакторинг дубликата кода, когда единственное отличие - это тип одной переменной? - PullRequest
4 голосов
/ 05 января 2012

Я должен иметь возможность подключаться к двум различным версиям API (1.4 и 1.5), назовем его Foo API. И мой код, который подключается к API и обрабатывает результаты, в значительной степени дублируется - единственное различие заключается в типах данных, возвращаемых двумя API. Как я могу реорганизовать это, чтобы удалить дублирование?

В Foo14Connector.cs (мой собственный класс, который вызывает API 1.4)

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 имеют идентичные свойства.

Ответы [ 3 ]

5 голосов
/ 05 января 2012

Если коннекторы находятся в разных проектах, эту ситуацию легко решить:

Добавить новый файл класса, назвать его ConnectorCommon и скопировать весь общий код, но с удаленными пространствами имен.Сделайте этот класс частичным классом и переименуйте класс (не файл) во что-то вроде Connector.

Вам нужно будет добавить ссылку на него в каждый проект.

Далее удалите всекод из ваших текущих классов соединителей, переименуйте класс (не обязательно файл) в тот же класс, что и частичный класс, и добавьте оператор 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
{
}

Обновление

Поначалу этот процесс может немного запутать.

Чтобы уточнить, вы делитесь исходным кодом в общем файле между двумя проектами.

Фактические классы - это конкретные классы с пространствами имен в каждом проекте.Вы используете ключевое слово part, чтобы общий файл был объединен с фактическим файлом проекта (т. Е. 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 голос
/ 08 января 2012

Если FooConnectors не запечатаны и вы можете создавать новые экземпляры, тогда вы можете получить свои собственные соединители и реализовать интерфейсы одновременно.В c # вы можете реализовать члены, просто унаследовав их от базового класса!

public IFooConnector {
    void GetAllCustomers();
}

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

, а затем

IFooConnector connector = new MyFoo14Connector();
connector.GetAllCustomers();
0 голосов
/ 05 января 2012

Вы должны представить интерфейс, который является общим для обеих реализаций. Если проекты написаны на одном языке и находятся в разных проектах, вы можете представить общий проект, на который ссылаются оба проекта. Затем вы переходите к наличию зависимостей только на вашем интерфейсе, что должно позволить вам переключаться между различными реализациями за кулисами где-нибудь, используя инверсию управления (Google, внедрение зависимостей или поиск служб или фабричный шаблон).

Трудности для вас могут быть:

1) Публичные статические методы в реализациях не могут быть статически доступны через интерфейс 2) Потенциально иметь код в одном классе реализации, т.е. Foo14Connector или Foo15Connector, который не имеет смысла помещать в универсальный интерфейс

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...