更新:关于我是如何实现解决方案的,请参阅问题的结尾。
很抱歉这个问题措辞不周,但我不知道该怎么问才好。我不知道如何设计一个可以重复使用的解决方案,在这种解决方案中,大多数代码在每次实现时都是完全相同的,但是实现的一部分每次都会改变,但遵循类似的模式。我试图避免复制和粘贴代码。
我们有一个内部数据消息传递系统,用于在不同机器上跨数据库更新表。我们正在扩展消息传递服务,将数据发送给外部供应商,我希望编写一个简单的解决方案,如果我们决定向多个供应商发送数据,就可以重用该解决方案。代码将被编译成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()发布于 2010-08-02 17:45:35
我会说使用依赖注射。基本上,您传递发送方法的抽象。
类似于:
interface IVendorMessageSender
{
void SendMessage(Vendor v);
}
public class OutboxManager
{
IVendorMessageSender _sender;
public OutboxManager(IVendorMessageSender sender)
{
this._sender = sender; //Use it in other methods to call the concrete implementation
}
...
}正如前面提到的,另一种方法是继承。
在任何一种情况下:尝试从该类中删除DB检索代码。为此使用另一个抽象(即:将一个IDataProvider接口或类似的东西传递给构造函数)。它将使您的代码更易于测试。
发布于 2010-08-02 16:19:05
有两种非常简单的方法:
OutboxManager成为一个抽象类,并为每个供应商提供一个子类。SendMessagesToVendor可以标记为抽象,迫使每个供应商重新实现它。这种方法很简单,非常适合OO原则,而且还允许您为其他方法提供实现,但如果希望稍后允许,仍然允许重写特定于供应商的版本。OutboxManager封装一些其他类或接口,这些类或接口提供了SendMessagesToVendor中所需的特定供应商信息。这很容易成为每个供应商都可以实现的小接口,SendMessagesToVendor可以使用这个接口实现来发送消息。这样做的好处是允许您在这里编写一些代码--可能减少供应商之间的重复。它还可能允许您的SendMessagesToVendor方法更一致,更容易测试,因为您只需要依赖这里所需的特定供应商功能。这也可能是作为一个相关(但略有不同)的方法传入的委托来实现的(不过,我个人更喜欢一个接口,而不是委托)。发布于 2010-08-02 16:22:25
如果使它成为一个抽象基类,因此必须继承它,则可以强制在具体对象中实现该方法。
using System;
using System.Collections.Generic;
public abstract class OutboxManagerBase
{
private List<string> _OutboxMsgs;
public 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.
}
protected abstract void SendMessagesToVendor();
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.
}
}
public class OutBoxImp1 : OutboxManagerBase
{
protected override void SendMessagesToVendor()
{
throw new NotImplementedException();
}
}https://stackoverflow.com/questions/3389588
复制相似问题