Как мне смоделировать мой код, чтобы максимизировать повторное использование кода в этой конкретной ситуации?

Обновлено: см. Конец вопроса о том, как я реализовал решение.

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

У нас есть внутренняя система обмена данными для обновления таблиц в базах данных на разных машинах. Мы расширяем нашу службу обмена сообщениями для отправки данных внешним поставщикам, и я хочу написать простое решение, которое можно использовать повторно, если мы решим отправить данные более чем одному поставщику. Код будет скомпилирован в EXE-файл и будет запускаться на регулярной основе для отправки сообщений в службу данных поставщика.

Вот приблизительное описание того, что делает код:

public class OutboxManager 
{
    private List<OutboxMsg> _OutboxMsgs;

    public void DistributeOutboxMessages()
    {
        try {
            RetrieveMessages();
            SendMessagesToVendor();
            MarkMessagesAsProcessed();
        }
        catch Exception ex {
            LogErrorMessageInDb(ex);
        }
    }

    private void RetrieveMessages() 
    {
      //retrieve messages from the database; poplate _OutboxMsgs.
      //This code stays the same in each implementation.
    }

    private void SendMessagesToVendor()   // <== THIS CODE CHANGES EACH IMPLEMENTATION
    {
      //vendor-specific code goes here.
      //This code is specific to each implementation.
    }

    private void MarkMessagesAsProcessed()
    {
      //If SendMessageToVendor() worked, run this method to update this db.
      //This code stays the same in each implementation.
    }

    private void LogErrorMessageInDb(Exception ex)
    {
      //This code writes an error message to the database
      //This code stays the same in each implementation.
    }
}

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

Я уверен, что есть хорошие объектно-ориентированные принципы, которые могут помочь мне решить эту проблему, но я не уверен, какой из них лучше всего использовать.

Это решение, в котором я остановился, вдохновленныйВиктор ответ а такжеОтвет Рида (и комментарии) использовать модель интерфейса. Существуют все те же методы, но теперь они спрятаны в интерфейсах, которые потребитель может обновить при необходимости.

Я не осознал всю мощь реализации интерфейса, пока не понял, что разрешаю потребителю класса подключать свои собственные классы для доступа к данным (IOutboxMgrDataProvider) и ведение журнала ошибок (IErrorLogger). Хотя я все еще предоставляю реализации по умолчанию, так как не ожидаю, что этот код изменится, для потребителя все еще возможно переопределить их своим собственным кодом. За исключением написания нескольких конструкторов (которыеЯ могу изменить на именованные и необязательные параметры), это действительно не заняло много времени, чтобы изменить мою реализацию.

public class OutboxManager
{
    private IEnumerable<OutboxMsg> _OutboxMsgs;
    private IOutboxMgrDataProvider _OutboxMgrDataProvider;
    private IVendorMessenger _VendorMessenger;
    private IErrorLogger _ErrorLogger;

    //This is the default constructor, forcing the consumer to provide
    //the implementation of IVendorMessenger.
    public OutboxManager(IVendorMessenger messenger)
    {
         _VendorMessenger = messenger;
         _OutboxMgrDataProvider = new DefaultOutboxMgrDataProvider();
         _ErrorLogger = new DefaultErrorLogger();
    }

    //... Other constructors here that have parameters for DataProvider
    //    and ErrorLogger.

    public void DistributeOutboxMessages()
    {
         try {
              _OutboxMsgs = _OutboxMgrDataProvider.RetrieveMessages();
              foreach om in _OutboxMsgs
              {
                  if (_VendorMessenger.SendMessageToVendor(om))
                      _OutboxMgrDataProvider.MarkMessageAsProcessed(om)
              }
         }
         catch Exception ex {
             _ErrorLogger.LogErrorMessage(ex)
         }
    }

}

//...interface code: IVendorMessenger, IOutboxMgrDataProvider, IErrorLogger
//...default implementations: DefaultOutboxMgrDataProvider(),
//                            DefaultErrorLogger()

Ответы на вопрос(7)

Ваш ответ на вопрос