【问题标题】:Using object type for information passing between modules使用对象类型在模块之间传递信息
【发布时间】:2012-04-23 17:51:16
【问题描述】:

我们有一个模块化的 MVVM 应用程序。其中一个界面如下所示

public interface ILogger
{

    void ReportError(ErrorType type);
}

ErrorType 类型如下所示

class ErrorType
{
  string Message;
  string Title;
  object Owner;
}

注意类型object。实现 ILogger 接口的模块只需从中调用 GetString(),因为它只需要调用模块的名称。对象的使用对我来说似乎是个问题。我们正在开发一个松散耦合的应用程序,并且我们允许在模块之间传递任何对象?

与可能导致拼写错误的字符串相比,justified as 对象的使用更加灵活并保证提供类型名称。接口的实现者除了调用 GetString() 之外什么也不做。

我请求一些建议。在我看来,对象的使用就像模块不知道如何在它们之间进行识别。像这样使用 object 是不是很好的设计?

我在考虑更多

 class ErrorType
 {
      string Message;
      string Title;
      string ModuleName;
 }

【问题讨论】:

    标签: c# design-patterns modularity


    【解决方案1】:

    如果您使用的只是对象的名称,那么我建议在创建 ErrorType 时只使用反射来传递它,而不是存储整个对象。您的开发人员必须确保不使用硬编码值,因为如果您担心拼写错误/可维护性,这是允许的。*

    但是,如果您出于任何其他原因需要该对象,则应保留它。否则,它只是不需要的开销。

    不过,只有我的两分钱。

    *Here is a SO question that shows how to get Current Method 以下是获取当前模块的方法:

    this.GetType().Module.Name;
    

    【讨论】:

    • @Jimmy 没问题,总是乐于助人!与往常一样,如果这是您正在寻找的内容,请勾选接受 :)
    【解决方案2】:

    既然string ModuleName 就是您现在所需要的,只需使用它即可。它将迫使您暴露最少的信息,其他模块将无法作弊并尝试根据 Owner 对象的类型做出任何决定。

    在实际代码中使用属性(最好在 IErrorType 接口上只读),因此很容易更改实现,即根据传入的对象计算 ModuleName。

    【讨论】:

      【解决方案3】:

      如果您尝试捕获堆栈信息(如模块名称),您应该真正考虑使用 Log4Net 或 NLog - 无需重新发明轮子。

      如果您的所有图层都在 .Net 中,我看不出使用 Object 类型会给您带来什么问题——它是其他所有内容的基类。问题是您将如何处理(或其他人将如何处理)这些信息?它只有 .ToString、.Equals 和其他几个方法。您是否有驱动日志设计的非功能性需求?如果(还)不需要“所有者”,请不要包含它。

      传递或不传递对象不一定会影响耦合;相反,它是多少一件事了解另一件事。所以不要添加你不需要的东西。

      【讨论】:

      • 请注意,我们关心模块之间使用的接口。传递对象的问题在于,模块需要从另一个模块获得什么并不明显。
      • 我没有看到你的规范,只需要调用模块的名称;如果是这种情况,我会使用 ModuleName 建议
      【解决方案4】:

      实现 ILogger 接口的模块只需要从这里调用 GetString(),因为它只需要调用模块的名称

      (小注:正确的方法名是ToString()

      那么,对于ILogger 需要,您有一个隐式接口。不妨让它显式,并强制模块实现它:

      interface INamed {
        string Name { get; }
      }
      

      然后(注意我如何将 ErrorType 重命名为 Error;其他名称,如 ErrorMessage 也可以):

      class Error {
        string Title;
        string Message;
        INamed NamedModule;
      }
      

      当然,拥有这样一个简单的界面,只是为了获得一个名字,可能有点矫枉过正;您可以按照您的提议使用string

      class Error {
        string Title;
        string Message;
        string ModuleName;
      }
      

      任何一种方式都比使用Object.ToString() 更好,因为它过于隐含并且不会传达其意图或强制您的模块 覆盖它。

      【讨论】:

        【解决方案5】:

        当我们需要的只是模块名称时,模块名称是可以的,但事实并非如此,在另一种情况下,需要一个 url 作为标识符,另一种情况是 url 和模块名称,那么我们该怎么办在这里?

        我不确定它是否只是所有者或模块名称,但我确实欣赏使用 object.tostring 的隐含性质。

        虽然我有一个是实际使用所有者对象的接口来识别调用者,例如 IDocument,它将 URL 和 Text 作为可能的值,然后日志服务的客户端将检查所有者是否属于类型 IDocument 并能够用它做更多的事情。

        肯定需要添加更多关于调用类的信息,而不仅仅是模块名称,有时甚至不需要。

        也许类继承可以提供帮助。

        Class Message
        {
           string Title {get; set;}
           string Message {get; set;}
        }
        
        Class ModuleMessage: Message
        {
           string ModuleName  {get; set;}
        }
        
        Class URLMessage: Message
        {
           string URL {get; set;}
        }
        
        Class DocumentMessage: URLMessage
        {
           string Text  {get; set;}
        }
        

        等等

        虽然这里的危险是你会因创建越来越多的类而忘乎所以,没有人知道他们应该使用哪个类。

        【讨论】:

        • 模块之间需要什么信息很重要,如果有一个新的数据结构或接口是有意义的,那就可以做到。只是传递一个物体会弊大于利。
        • 但我可以将您推荐回您设置为答案的评论,这表明模块名称应该是基于传入对象的只读属性...因此暗示该对象已给出到 Error 类并通过接口作为字符串公开 - 模块名称...
        猜你喜欢
        • 2015-08-21
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-04-03
        • 1970-01-01
        相关资源
        最近更新 更多