2016-11-11 2 views
2

Я дам вам немного контекста первыйКак перегрузить/заменить/продлить C# Интерфейс, используемый в общем коде

Моя компания выбрала подход к проектированию для наших приложений (окна услуг), чтобы позволить большему количеству повторного использования кода за счет централизации (внутренний nuget repo) основного кода. Это упрощает ведение тестирования и создание новых сервисов до сих пор.

По существу, все службы используют SqlDependency для получения уведомления из базы данных, которая доступна для обработки. Когда объект SqlDependency получает уведомление, что вызывает следующий

public interface IRequestReceiver : IDisposable 
{ 
    IEnumerable<IRequest> GetRequests(int maxRequestNumber); 
} 

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

Теперь для задачи

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

Моя проблема заключается в том, что я не могу изменить IRequest, поскольку он используется несколькими живыми службами, и я обязан придерживаться шаблона проектирования наших существующих сервисов, но я должен включать дополнительные ресурсы сервера в IRequest, которых раньше не было, и не имеет отношения к существующим услугам.

И, наконец, мой вопрос

Учитывая, я знаю, что интерфейс представляет собой договор, и поэтому не должен быть перегружен, как бы я перегрузить или расширить или даже заменить существующий IRequest интерфейса для всего этого нового сервиса, не подвергая нерелевантные свойства к существующим услугам.

Ниже приведены образцы существующего и нового IRequest интерфейса

Existing

public interface IRequest 
{ 
    int Id { get; } 

    string CreatedBy { get; } 

    bool IsActive { get; set; } 

    DateTimeOffset CreatedDateTime { get; set; } 

    string LastUpdatedBy { get; set; }# 

    DateTimeOffset LastUpdatedDateTime { get; set; } 

    IRequestDetail Detail { get; } 

    bool Process(CancellationToken token); 
} 

Новый

public interface IRequest 
{ 
    int Id { get; } 

    string CreatedBy { get; } 

    bool IsActive { get; set; } 

    DateTimeOffset CreatedDateTime { get; set; } 

    string LastUpdatedBy { get; set; }# 

    DateTimeOffset LastUpdatedDateTime { get; set; } 

    int NotificationId { get; set; } 

    int StatusId { get; set; } 

    string StatusCode { get; set; } 

    string StatusMessage { get; set; } 

    string Destination { get; set; } 

    string BusinessProcessCode { get; set; } 

    string MsgType { get; set; } 

    string MessageId { get; set; } 

    bool Process(CancellationToken token); 
} 

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

Спасибо

+0

Новый интерфейс и использовать его для частей, которые требуют новых свойств. Для получения дополнительной информации читайте здесь: http://stackoverflow.com/questions/8042/extension-interface-patterns – sr28

+0

sr28 Я не уверен, что это применимо в качестве расширений - это методы? в то время как я особенно фокусируюсь на свойствах, которые я хочу расширить. спасибо – GuildBK

ответ

-1

Создание интерфейса V2, который либо является производным от первоначальной версии или является полностью независимым от него (потребуется совсем немного больше работы). Затем используйте V2, где вам это нужно: проверьте, является ли запрос V2, отбрасывает объект, а затем вызывает свойства V2.

Возможно, это будет довольно некоторая работа, чтобы включить свойства V2 везде, где это необходимо. Если это невозможно, вы можете выбрать, чтобы две отдельные системы были живы, работали бок о бок.

+0

Не могли бы вы рассказать об этом? Как я могу обойти проблему, связанную с тем, что V1 содержит элементы, которые не нужны V2, или знать, как их создать, например IRequestDetail? Спасибо – GuildBK

+0

Возможно, вам придется поместить все общие свойства в общий интерфейс. Затем выведите его в интерфейсе V1 и V2. –

+0

ok, поэтому опция 2 (работа с двумя службами бок о бок) не является бегуном (временные рамки и бюджет). Что касается варианта 1, я мог бы создать новую версию этого интерфейса в nuget и развернуть его, а затем сохранить существующие службы на старой версии до тех пор, пока я не обошел их рефакторинг в общий интерфейс с интерфейсом v1 и v2 под ним. – GuildBK

1

Подумайте о принципе открытого закрытого типа.

У вас уже установлен IRequest. У вас есть клиенты, которые уже используют IRequest в производстве.

Что вам нужно, это новые клиенты (или старые), которые хотели бы использовать новые функции.

Так что в двух словах. 1. Ничего не изменится в IRequest 2. сделайте вместо IRequest расширений, например:

public interface IRequestExtensions 
{ 
    int NotificationId { get; set; } 

    int StatusId { get; set; } 

    string StatusCode { get; set; } 

    string StatusMessage { get; set; } 

    string Destination { get; set; } 

    string BusinessProcessCode { get; set; } 

    string MsgType { get; set; } 

    string MessageId { get; set; } 
} 

Однако то, что я вижу в том, что в новом IRequest является то, что у вас есть обратные несовместимые типы. Для этого объяснения (поскольку вы не упомянули о несовместимых типах), я не включил их в IRequestExtensions.

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

public interface IRequestNew : IRequest, IRequestExtensions 
{ 
} 

Теперь новые (и старые существующие) клиенты должны использовать IRequestNew (только имя, не очень, но вы получите идею) и для старых клиентов, которые хотят реализовать новый интерфейс будет просто добавить дополнительные, IRequestExtension к их классу.

Как вы перенаправляете всех, чтобы использовать IRequest в качестве настоящего нового имени со всеми функциями. Ну, это еще одна история.

0

Другой способ решения этой проблемы является использование универсального метода для GetRequests

IEnumerable<T> GetRequests<T>(int maxRequestNumber); 

Но класс, который вызывает GetRequest должны знать, что тип они ожидают. Если они ожидают IRequestOld/IRequestNew, они должны передать его при вызове GetRequests.

IRequestOld request = GetRequest<RequestOld>(maxRequestNumber); 
IRequestNew request = GetRequest<RequestNew>(maxRequestNumber); 

Пример программы

class Program 
{ 

    public static void Main() 
    { 
     Number n = new Number(); 
     IOne one = n.GetNumberObject<One>(); 
     one.PrintOne(); 
     ITwo two = n.GetNumberObject<Two>(); 
     two.PrintTwo(); 
    } 

    public interface INumbers 
    { 
     T GetNumberObject<T>() where T : new(); 
    } 
    public class Number : INumbers 
    { 
     public T GetNumberObject<T>() where T : new() 
     { 
      return new T(); 
     } 
    } 

    public interface IOne 
    { 
     void PrintOne(); 
    } 
    public interface ITwo 
    { 
     void PrintTwo(); 
    } 

    class One : IOne 
    { 
     public void PrintOne() 
     { 
      Console.WriteLine("One"); 
     } 
    } 
    class Two : ITwo 
    { 
     public void PrintTwo() 
     { 
      Console.WriteLine("Two"); 
     } 
    } 
} 
Смежные вопросы