【问题标题】:Best design method to allow user to change a class method - Delegates/Inheritance/Interface?允许用户更改类方法的最佳设计方法-委托/继承/接口?
【发布时间】:2017-11-26 18:16:27
【问题描述】:

我正在写class Movies,为简单起见,我负责添加/删除/保留一组电影。电影实例有许多参数,例如长度、颜色、流派等。Movies 还应该允许用户调用 Movie bestMovie(),这将返回集合中'最好的'电影。

假设我已经有两种选择最佳电影的方法(一种基于最高 IMDB 排名,另一种基于 Rotten Tomatoes)但我希望允许用户添加新类型的决策算法(例如基于长度 +一年中的季节)例如。实现这一点的最佳设计是什么?

我的想法:

  1. 允许用户从Movies 继承并覆盖bestMovie()。感觉像是继承的错误用法。
  2. 创建一个名为MovieSelection 的接口并实现class IMDBMovieSelection。然后用户可以添加class SeasonMovieSelectionMovies 然后,Ctor 将获得 MovieSelection 作为参数,它将在 bestMovie() 中使用 - 创建对象只是为了向我的主要对象“发送信号”方法感觉是错误的
  3. 在调用 bestMovie(<anonymous function>) 时使用委托/匿名函数(类似于我对 List.Sort(IComparable) 使用的函数) - 感觉不可扩展且难以维护,尤其是在函数很复杂的情况下。
  4. 提供使用部分类扩展类的能力 - 甚至不确定这是否是一个真正的选择

在此不胜感激。我确定我不是第一个遇到这个问题的人,但不知道具体要搜索什么。

谢谢

【问题讨论】:

    标签: c# design-patterns polymorphism


    【解决方案1】:

    我同意这不是继承的理想选择(#1)。这听起来像是strategy pattern 的一个很好的用例,这基本上只是意味着将您的算法封装在一个类中,以便您可以随时更换。因此,也许您的 Movie 类是使用默认策略(例如,最高 IMDB 评级)初始化的,但可以根据用户选择动态更改。这最接近您的选项#2。拥有基本上只是将消息中继到另一个对象的方法可能会让人感觉很奇怪,但这比继承提供了更好的灵活性。

    【讨论】:

    • 虽然我同意您的回答,但您可以通过添加一个最小的代码示例来说明策略模式,使其变得更好。无论如何 +1。
    【解决方案2】:

    我会使用 Collections 使用的方式,我的意思是基本上你应用 OrderBy 过滤器,然后应用 First 函数。 有了这个,我们有两个选择:

    1. 使用IComparable<in T> 接口来利用集合的排序算法。

    例子:

    public class Movies
    {
     List<Movie> Items {get; set; }
     IComparable<Movie> DefaultImplementation = new DefaultCompareImplementation();
     //...
     //...
    
        public Movie bestMovie(IComparable<Movie> comparer = null)
        {
          var compare = comparer ?? DefaultImplementation;
          return Items.Sort(compare).First()
        } 
    }
    
    1. 使用Func&lt;TSource,TKey&gt; 之类的委托和默认实现,以防用户不提供任何委托。

    例子:

    public class Movies
    {
     List<Movie> Items {get; set; }   
     //...
     //...
    
        public Movie bestMovie<TKey>(Func<Movie,TKey> orderBy = null)
        {
          var compare = orderBy ?? (movie)=> movie.Rating;
          return Items.OrderBy(compare).First()
        } 
    }
    

    对于上面提到的strategy pattern,我会这样使用它:

    IMovieSelection 接口:

    public interface IMovieSelection 
    {
        Movie FindBestMovie(IEnumerable<Movie> items);
    }
    

    ImdbRatingSelection 类:

    public class ImdbRatingSelection:IMovieSelection 
    {
       public Movie FindBestMovie(IEnumerable<Movie> items)
        {
           return items.OrderBy(movie=>movie.Rating).FirstOrDefault();
        }
    }
    

    电影类:

    public class Movies
    {
     public enum ImplementedStrategies{ ImdbRating }
     List<Movie> Items {get; set; }   
     //...
     //...
    
        public Movie bestMovie(ImplementedStrategies strategy = ImplementedStrategies.ImdbRating)
        {
           switch(strategy)
           {
             case ImplementedStrategies.ImdbRating:
               return new ImdbRatingSelection().FindBestMovie(Items);
             default: 
                throw new ArgumentOutOfRangeException(nameof(strategy), strategy, null);
           }
        }
    
        public Movie bestMovie(IMovieSelection customSelection)
        {
          return customSelection?.FindBestMovie(Items) ?? bestMovie();
        }
    }
    

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2020-03-29
      • 2020-10-04
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多