【问题标题】:Are (a lot of) internal methods avoidable? (interface, factory pattern)(很多)内部方法可以避免吗? (接口,工厂模式)
【发布时间】:2019-05-20 08:46:19
【问题描述】:

我目前正在开发一个机器人,并且有大约 8 个用于不同对话框的单独类(都在同一个命名空间中!)。它们都包含不同的任务,因此我遇到了一个小问题。 我想知道最佳实践是什么:使用接口,使用工厂模式……然而,所有这些选项都迫使我使用内部方法。 (我通过接口得到它,因为你承诺某些行为,但是对于工厂模式我真的不知道 - 老实说......)因为没有特定方法的定义 - 但这意味着我必须做出很多这些内部方法,我试图避免冗余。

首先我只是实例化了一个新对象,但我很快意识到这意味着每次调用机器人时都会创建一个各种类型/对话的新对象 - 这不是很有效,对吧?我也尝试在构造函数中实例化它们,但这迫使我使用接口,这给我带来了与我之前所说的相同的问题。我也研究了部分类,但我不确定使用 8 个部分类是否真的......好吗?

现在我正在使用以下代码尝试工厂模式: (此主题的致谢:How to prevent an instantiation of an object in c#

public class DialogFactory
    {
        private NameDialog _nameDialog;
        private CertificateDialog _certificateDialog;
        private ProfileDialog _profileDialog;
        private ClassDialog _classDialog;
        private LocationDialog _locationDialog;
        private SkillDialog _skillDialog;
        private EducationDialog _educationDialog;
        private SpecializationDialog _specializationDialog;

        public DialogFactory CreateDialog(string dialog)
        {
            switch (dialog.ToLower())
            {
                case "name": return new NameDialog();
                case "certificate": return new CertificateDialog();
                case "profile": return new ProfileDialog();
                case "class": return new ClassDialog();
                case "location": return new LocationDialog();
                case "skill": return new SkillDialog();
                case "education": return new EducationDialog();
                case "specialization": return new SpecializationDialog();
                default: throw new Exception("That dialog does not exist.");
            }

            throw new Exception("That dialog does not exist.");
        }
    }

为了给出对话框看起来的一些上下文,我还将在此处添加名称对话框:

public class NameDialog : DialogFactory
    {
        ProfileService profileService = new ProfileService();

        public async Task AddNameResponse(ITurnContext turnContext, Profile profile, string value { … }
     }

我尝试在 main 方法中访问 AddNameResponse 任务,如下所示:await dialog.CreateDialog("name").AddNameResponse(turnContext, profile, value); 这不被接受,但是给了我以下警告:“DialogFactory”不包含“AddNameResponse”的定义,并且没有可访问的扩展方法“AddNameResponse” ' 接受 'DialogFactory' 的第一个参数。修复将是一个内部任务,但我试图避免这种情况(之前给出的原因)。

我真的很茫然,因为我不知道最佳做法是什么。我正在尝试制作我可以制作的最有效和最干净的代码,并避免冗余并尽可能多地使用松散耦合 - 但我不知道如何在这种情况下实现这一点...... 我希望我已经很好地阐述了我的问题(也是问题)!

【问题讨论】:

  • however, force me to use internal methods - 但为什么呢?对于具有name 属性和show(dialogContext) 方法的IDialog,这似乎是一个相当正常的用例?为什么你不这么认为?
  • 是否允许机器人同时打开多个对话实例?如果不是,那么是的,您可能希望实例成为单例以节省内存,但是,我不确定您为什么需要工厂来执行此操作。这些Tasks 是否存在是因为 IO 是异步的(通过网络?)并且您需要等待对机器人的请求/响应?如果您想避免实例化 - 您可以创建一个静态类并通过该类使所有实例可访问您在调用 CreateDialog 方法时无法访问实例方法,因为您返回的是工厂本身而不是对话框实例...跨度>
  • @MatJ 我也在想是的!但是因为 IDialog 也将用于所有其他对话框,这意味着我必须在这些对话框中创建内部类,因为使用接口时承诺的行为。这将导致其他 7 个内部任务,反之亦然,在我看来这不是很干净..
  • CreateDialog 的返回类型是DialogFactory - 但这意味着所有对话框实例都将从DialogFactory 继承,然后您将拥有FactoryCeption。这绝对是你的代码吗?
  • 如果您对应该呈现的对话框有足够的了解并且想要对其做出响应,那么通用 解决方案很可能不是正确的选择。为什么不能直接new NameDialog().AddNameResponse(...)呢?

标签: c# interface factory-pattern redundancy internal-class


【解决方案1】:

工厂模式对多态很有意义。这意味着,例如,我们想要一个IDialog,而我们并不关心实现是什么。我们不想知道。这样,我们的代码就依赖于IDialog,并且不与任何实现它的特定类耦合。

如果您尝试这样做:

dialog.CreateDialog("name").AddNameResponse(turnContext, profile, value);

...错误是从 dialog.CreateDialog("name") 返回的任何内容都没有 AddNameResponse 方法,这表明您的代码依赖于比工厂返回的更具体的类。

工厂不会减少耦合有几个原因:

  • 您的代码仍然依赖于NameDialog。您需要具有 AddNameResponse 方法的确切类。
  • 即使工厂返回了确切的类,现在您也已耦合到工厂该类。

您希望减少耦合是有道理的,因为如果一个类与NameDialog 相关联,那么它也与ProfileService 相关联。如果不依赖ProfileService,就无法测试依赖于NameDialog 的类。

潜在的解决方案将涉及更改依赖于NameDialog 的类。以下是一些想法:

  • 定义一个抽象(例如接口或委托)来描述您的类需要对NameDialog 执行的操作。将其注入您的班级。现在您的类依赖于抽象类,而不是具体类。
  • 如果NameDialog 做了一些非常简单的事情,也许您可​​以注入它而不是抽象,更好的解决方法是定义一个代表ProfileService 的抽象并将其注入NameDialog
  • 可能两者都做。

这些都意味着你是

  • 通过依赖抽象来避免耦合
  • 让您的依赖注入/IoC 容器负责创建对象

这比将所有这些对象的创建合并到一个工厂中效果更好。这种方法只有在工厂返回的任何对象都可以替代任何其他类型时才有意义——您不需要知道具体类型是什么。

【讨论】:

  • 为 DI 竖起大拇指 - 使用已注册的单例实例进行依赖注入将使这个设置变得轻而易举,即使结果解析返回一个具体的类 - 它仍然比耦合到工厂或新建实例更好需要,尤其是在以后复杂性增加的情况下。
  • 感谢您的回答!我研究了依赖注入(我以前不熟悉它,所以这是一个很好的提示),发现使用 ASP.NET 很容易实现(docs.microsoft.com/en-us/aspnet/core/fundamentals/…)。我还重构了我的代码并添加了两个接口 - 但是现在 Dialog 接口有时确实使用了错误的对象。我正在考虑使用策略模式来解决这个问题,但我想知道您对此事有何看法?
  • 我不知道为什么接口有时会使用错误的对象。我建议对它进行大量试验。三年前很难提到 DI,因为它就像打开一大罐蠕虫一样,但现在它更加熟悉,因为它是 ASP.NET Core 的一部分。这比我意识到的更有帮助,因为现在每个人都接触到了它。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2020-12-27
  • 2021-08-20
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-06-22
  • 2023-03-23
相关资源
最近更新 更多