首页
学习
活动
专区
圈层
工具
发布
首页
学习
活动
专区
圈层
工具
MCP广场
社区首页 >问答首页 >在这种特定情况下,我应该如何建模代码以最大限度地重用代码?

在这种特定情况下,我应该如何建模代码以最大限度地重用代码?
EN

Stack Overflow用户
提问于 2010-08-02 16:12:40
回答 7查看 469关注 0票数 11

更新:关于我是如何实现解决方案的,请参阅问题的结尾。

很抱歉这个问题措辞不周,但我不知道该怎么问才好。我不知道如何设计一个可以重复使用的解决方案,在这种解决方案中,大多数代码在每次实现时都是完全相同的,但是实现的一部分每次都会改变,但遵循类似的模式。我试图避免复制和粘贴代码。

我们有一个内部数据消息传递系统,用于在不同机器上跨数据库更新表。我们正在扩展消息传递服务,将数据发送给外部供应商,我希望编写一个简单的解决方案,如果我们决定向多个供应商发送数据,就可以重用该解决方案。代码将被编译成EXE并定期运行,以便向供应商的数据服务发送消息。

下面是代码的大致轮廓:

代码语言:javascript
运行
复制
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)插入他们自己的类之前,我才意识到接口实现的威力。虽然我仍然提供默认实现,因为我不期望这段代码会改变,但使用者仍然可以用自己的代码覆盖它们。除了编写多个构造函数(其中的我可以更改为命名参数和可选参数。)外,更改我的实现并不需要花费太多时间。

代码语言:javascript
运行
复制
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()
EN

回答 7

Stack Overflow用户

回答已采纳

发布于 2010-08-02 17:45:35

我会说使用依赖注射。基本上,您传递发送方法的抽象。

类似于:

代码语言:javascript
运行
复制
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接口或类似的东西传递给构造函数)。它将使您的代码更易于测试。

票数 1
EN

Stack Overflow用户

发布于 2010-08-02 16:19:05

有两种非常简单的方法:

  1. 使OutboxManager成为一个抽象类,并为每个供应商提供一个子类。SendMessagesToVendor可以标记为抽象,迫使每个供应商重新实现它。这种方法很简单,非常适合OO原则,而且还允许您为其他方法提供实现,但如果希望稍后允许,仍然允许重写特定于供应商的版本。
  2. OutboxManager封装一些其他类或接口,这些类或接口提供了SendMessagesToVendor中所需的特定供应商信息。这很容易成为每个供应商都可以实现的小接口,SendMessagesToVendor可以使用这个接口实现来发送消息。这样做的好处是允许您在这里编写一些代码--可能减少供应商之间的重复。它还可能允许您的SendMessagesToVendor方法更一致,更容易测试,因为您只需要依赖这里所需的特定供应商功能。这也可能是作为一个相关(但略有不同)的方法传入的委托来实现的(不过,我个人更喜欢一个接口,而不是委托)。
票数 9
EN

Stack Overflow用户

发布于 2010-08-02 16:22:25

如果使它成为一个抽象基类,因此必须继承它,则可以强制在具体对象中实现该方法。

代码语言:javascript
运行
复制
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();
    }
}
票数 2
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/3389588

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档