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