Обновлено: см. Конец вопроса, чтобы узнать, как я реализовал решение.
Извините за плохо сформулированный вопрос, но я не был уверен, как лучше его задать.Я не уверен, как спроектировать решение, которое можно будет повторно использовать, когда большая часть кода будет одинаковой при каждой реализации, но часть реализации будет меняться каждый раз, но следовать аналогичным шаблонам.Я пытаюсь избежать копирования и вставки кода.
У нас есть внутренняя система обмена данными для обновления таблиц в базах данных на разных машинах.Мы расширяем нашу службу обмена сообщениями для отправки данных внешним поставщикам, и я хочу написать простое решение, которое можно использовать повторно, если мы решим отправить данные более чем одному поставщику.Код будет скомпилирован в 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()