【问题标题】:Two functions, or one function with different params?两个函数,还是一个具有不同参数的函数?
【发布时间】:2009-05-07 22:06:55
【问题描述】:

这是一个非常通用的“最佳实践”问题,但这里有一个示例。

假设我有一个电影编目应用程序。我想让我的用户有机会为他们的概要/评级信息指定 IMDb 或 Metacritic。

我会这样做吗:

if (preferredSupplier == "imdb"){
      getIMDbRating(movieName);
}else{
      getMetacriticRating(movieName);
}

或者这个:

getRating(movieName, preferredSupplier);

我更喜欢第二个,但这意味着函数必须遵循完全不同的逻辑,具体取决于第二个参数的值(例如 Metacritic 可能需要屏幕抓取,而 IMDb 可能有一个不错的 API)。

或者我应该将它们结合起来吗?就像 getRating() 充当包装函数一样,根据第二个参数的值调用 getIMDbRating() 或 getMetacriticRating()。

【问题讨论】:

  • 你实际拥有的是一个 RatingSupplier 接口,它有一个 getRating(movieName) 函数并在 IMDbRatingSupplier 和 MetacriticRatingSupplier 类中实现?然后你有一个……过度设计的 FTW!
  • 哇,我打盹,我输了...他们说什么...
  • 有一点需要注意,这假设 IMDB 评级和 Metacritic 评级属于同一类型。您的返回值 range 不应因您的输入而异。
  • @devinb 您可以将评级标准化为一个范围,而不管提供者如何。

标签: parameters function


【解决方案1】:

第二个允许您随着时间的推移扩展首选供应商的数量,您仍然可以(在内部)将这些作为两种单独的方法来实施。

如果是我,我会研究两个类(Imdb 和 Metacritic),它们都派生自 RatingProvider 基类,并以不同的方式实现 getRating。

或者,如果我戴上 Patterns 的帽子,我会看 Bridge 模式。

只有您知道系统中可能发生的变化在哪里,因此您知道是否需要对此进行深入研究,但是一个 API 可以让您以统一的方式获取评分,而不管它们实际来自哪里,我,成为一个比你必须通过选择一种方法或另一种方法来做出这些决定的 API 更好的 API。

【讨论】:

  • hmm...我比我的回答更喜欢这个想法:) 我应该想到的。不过,我会在您的答案中添加一件事:您应该有某种工厂(或只是一个工厂方法),它可以从参数创建这些对象,类似于 OP 示例中 getRating() 的工作方式。
  • 看看我的cmets。有趣的是,人们几乎同时在想同样的事情:)
  • 我和 rmeador 在一起。类似于 RatingProviderFactory.GetRatingProvider(string name),返回一个 IRatingProvider。然后 IRatingProvider 将具有 getRating 方法。恕我直言,这有点复杂但值得。
【解决方案2】:

拥有一个带有 getRating 方法的 RatingProvider 类可能是个好主意。

您可以有不同的评级提供者作为其子类,它们将有自己的实现来获取/处理评级。

【讨论】:

    【解决方案3】:

    这两种解决方案都不理想。您真正应该做的是使用 GetRating(string moviename) 函数将 preferredSupplier 实现为接口或抽象类。

    然后实现类 IMDBSupplier 和 MetaCriticSupplier 的接口,并让每个类放入它自己的逻辑以获得评级。这使得 getRating() 函数完全独立于使用它的任何代码,这是一个很好的松散耦合设计。

    在消耗供应商的类中,它不关心它是哪种类型 - 它只是调用 GetRating()。 GetRating() 与消费者无关。

    【讨论】:

      【解决方案4】:

      我将定义一个名为 MovieDatabase 的抽象类和一个名为 getRating 的抽象方法,然后为各种提供者(如 IMDb、Metacritic)提供实现 getRating 方法的子类。

      通过此设置,您可以编写与提供程序无关的代码,即对特定提供程序一无所知。它只需要一个 MovieDatabase 实例并对其调用 getRating 操作,而不用担心提供者或实现细节。

      这种方法的优点是可扩展性更强。如果您想添加更多提供程序或操作,您可以在一个地方(MovieDatabase 类及其子类)执行此操作,其余代码应该可以正常工作。

      【讨论】:

        【解决方案5】:

        我会把它们结合起来。正如您所说,这两者可能需要完全不同的实现,并且将实现代码分成不同的函数可以使事情更具可读性和更易于维护。但是有一个单一的呼叫点也很好。您可以考虑将它放在一个类中,将实现函数标记为私有,并将包装器标记为公共。这样,包装是唯一的接触点。通过明确包装器是这些函数的单一调用点,这将进一步提高可维护性。

        【讨论】:

          【解决方案6】:

          我更喜欢你的最后一个想法:两者都用。拥有一个将源作为参数的函数可以很容易地编写大量代码,这些代码通过简单的值更改(可能来自 UI)从供应商切换到供应商。如果/当您打算与固定的已知供应商通话时,您还可以使用方便的单一供应商功能来调用。

          【讨论】:

            【解决方案7】:

            第二个选项是最好的(顺便说一句,在 OO 中它被称为工厂)。给它一个默认行为,并在其中为每个提供者调用不同的函数,所有这些 if 都没有意义。

            【讨论】:

              【解决方案8】:

              我相信这取决于您使用这些方法的频率、从哪里使用以及代码的不同之处。请记住,编写 routine 的主要原因是它们是 - 没错 - routine。也就是说,例程应该包含您想要重用的代码,并且应该以易于重用的方式编写。

              话虽如此,如果我面对您的示例案例(并且正在使用 C# 进行编码),我可能最终会为不同类型的数据库搜索创建一个 enum,然后有一个包装方法接受这样的 enum作为参数,并从包装器方法调用不同的数据收集方法 - 类似于您在帖子末尾建议的方法,但不是使用字符串作为输入。

              【讨论】:

                【解决方案9】:

                这不是取决于您使用它的频率吗?如果您在整个代码中一遍又一遍地进行基本检查,那么一个函数将使您免于重复该代码块。

                但是,如果您只在各处使用该逻辑几次,那么使用第一种方式可能会更清楚。

                【讨论】:

                  【解决方案10】:

                  如果您的函数返回相同类型的响应,则在单个函数中重载是有意义的。

                  如果你的函数根据输入返回非常不同的东西,你可能应该使用两个函数来区分它们返回不同的东西。

                  例如,如果 IMDB 评级是 5 星等级,Metacritic 评级是 4 星等级,您需要明确说明它们应该以不同的方式处理。

                  使用单独的类将有助于澄清,而不是将所有这些功能都放在外面。

                  【讨论】:

                    【解决方案11】:

                    为什么你不能做类似的事情

                    public interface IRating{
                    
                      public Rating getRating();
                    }
                    
                    public IMDBRating extends Rating
                    
                    public MetacriticRating extends Rating
                    

                    【讨论】:

                      猜你喜欢
                      • 1970-01-01
                      • 1970-01-01
                      • 2022-01-13
                      • 2016-04-19
                      • 2014-01-31
                      • 1970-01-01
                      • 1970-01-01
                      • 1970-01-01
                      • 2017-07-19
                      相关资源
                      最近更新 更多