【问题标题】:Polymorphic object creation without IF condition没有 IF 条件的多态对象创建
【发布时间】:2017-04-07 12:56:42
【问题描述】:

我有一个这样的抽象类:

public abstract class Records
    {
        public string Type;
        public string Source;
        public int Value;

        protected Records(string type, string source, int value)
        {
            Type = type;
            Source = source;
            Value = value;
        }
}

我想创建许多继承这个类的类,并用来自静态类的值填充它们的类型字段,如下所示:

public static class ContentTypesString
    {
        public static string DocumentNew { get { return "Document - New this Month"; }}

        public static string HeadlinesNew { get { return "Headlines - New this Month"; }}

       etc...  
    }

我希望能够在没有测试“if foo == "document" then type = ContentTypesString.DocumentNew”或等效开关案例的情况下创建这些子类(我真的有很多案例)

是否有适合我需要的设计模式?

编辑:正如几个人指出的那样,我应该展示我如何创建我的实例。

     private delegate SPListItemCollection Query(SPWeb web, DateTime startDate, DateTime endDate);
     private readonly Query _queries;

       #region Constructors

      public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
          {
            if (web == null) throw new ArgumentNullException("web");

            _web = web;
            _startTimeSelectedDate = startTimeSelectedDate;
            _endTimeSelectedDate = endTimeSelectedDate;
            RecordsList = new List<Records>();

            // Query Invocation List
            _queries = NumberPagePerMonthQuery.PreparedQuery;
            _queries += NumberDocumentsPerMonthQuery.PreparedQuery;
            _queries += NumberHeadlinesPerMonthQuery.PreparedQuery;
            _queries += NumberLeaderboxPerMonthQuery.PreparedQuery;
            _queries += NumberNewsPerMonthQuery.PreparedQuery;
            _queries += NumberPagesModifiedPerMonthQuery.PreparedQuery;
            _queries += NumberPicturesPerMonthQuery.PreparedQuery;
            _queries += NumberTeasingPerMonthQuery.PreparedQuery;
        }

        #endregion Constructors

        #region Public Methods

        // what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
        /*** NO C#6 compiler in VS2012... ***/
        public void Queries()
        {
            foreach (var del in _queries.GetInvocationList())
            {
                var queryresult =
                    (SPListItemCollection) del.DynamicInvoke(_web, _startTimeSelectedDate, _endTimeSelectedDate);

                RecordsList.Add(new Records(del.Method.Name, _web.Title, queryresult.Count));
            }
        }

编辑²: 我选择的解决方案

  public List<IQuery> QueryList { get; } // no delegate anymore, and static classes became implementations of IQuery interface.

       #region Constructors

      public QueryHandler(SPWeb web, DateTime startTimeSelectedDate, DateTime endTimeSelectedDate)
          {
            if (web == null) throw new ArgumentNullException("web");

            _web = web;
            _startTimeSelectedDate = startTimeSelectedDate;
            _endTimeSelectedDate = endTimeSelectedDate;
            RecordsList = new List<Records>();

            QueryList = new List<IQuery>
            {
                new NumberDocumentsPerMonthQuery(),
                new NumberHeadlinesPerMonthQuery(),
                new NumberLeaderboxPerMonthQuery(),
                new NumberNewsPerMonthQuery(),
                new NumberPagePerMonthQuery(),
                new NumberPagesModifiedPerMonthQuery(),
                new NumberPicturesPerMonthQuery(),
                new NumberTeasingPerMonthQuery()
            };

        }

        #endregion Constructors

        #region Public Methods

        // what about NullReferenceException ? C#6 : item?.Foreach(item => {}); ?
        /*** NO C#6 compiler in VS2012... ***/
          public void Queries()
        {
            foreach (var query in QueryList)
            {
                var queryresult = query.PreparedQuery(_web, _startTimeSelectedDate, _endTimeSelectedDate);
                RecordsList.Add(query.CreateRecord(_web.Title, queryresult.Count));
            }
        }

记录类遵循@dbraillon 建议的实现 IQuery接口的实现被添加了方法:

public Records CreateRecord(string source, int value)
        {
            return new ModifiedPagesPerMonthRecord(source, value); //or another child of Record class. 
        }

然后瞧。谢谢大家的帮助。

【问题讨论】:

  • 为什么不在继承的类里面做呢? public class Documents : Records { public Documents() { Type = ContentTypesString.DocumentNew; } }
  • 为什么不放一些虚拟方法getDefaultContentTypeString?
  • 是的,但是如果没有调用者中的 IF,我该如何选择要制作的 Records 子项?
  • @Will :是的,构造函数名称有错误。已更正。谢谢
  • @YthioCsi 在什么来电者中?你的问题没有意义。

标签: c# oop


【解决方案1】:

您想通过对象类型的字符串代码和参数来收集记录。

其中一种方法 - 使用构建器。

首先我们需要配置builder:

        var builder = new RecordBuilder()
            .RegisterBuilder("document", (source, value) => new Document(source, value))
            .RegisterBuilder("headlines", (source, value) => new Headlines(source, value));

这里我们指定如何使用代码“文档”和“标题”来构建记录。

要建立录音通话:

        builder.Build("document", "source", 1);

生成器代码可以像这样 (这里我们看看我们是否知道如何构建传递类型的记录并制作它):

public class RecordBuilder
{
    public Records Build(string code, string source, int value)
    {
        Func<string, int, Records> buildAction;

        if (recordBuilders.TryGetValue(code, out buildAction))
        {
            return buildAction(source, value);
        }

        return null;
    }

    public RecordBuilder RegisterBuilder(string code, Func<string, int, Records> buildAction)
    {
        recordBuilders.Add(code, buildAction);
        return this;
    }

    private Dictionary<string, Func<string, int, Records>> recordBuilders = new Dictionary<string, Func<string, int, Records>> ();
}


public class Document : Records
{
    public Document(string source, int value) : base(ContentTypesString.DocumentNew, source, value)
    {
    }
}

public class Headlines : Records
{
    public Headlines(string source, int value) : base(ContentTypesString.HeadlinesNew, source, value)
    {
    }
}

【讨论】:

  • 我不确定我是否理解你在这里做什么以及如何使用它,但它看起来更像是我试图在这里重现的设计的(非常)模糊的记忆。
  • 我想我发现,我改变了我的程序很多。保存preparedQuery 的静态实用程序方法变成了IQuery 接口的实现,委托已被List 替换,委托调用列表由调用接口方法的list 上的foreach 替换。 IQuery 接口的实现还包含一个返回所需 Record 子实例的方法。
【解决方案2】:

这是你需要的吗?

public abstract class Records
{
    public string Type;
    public string Source;
    public int Value;

    protected Records(string type, string source, int value)
    {
        Type = type;
        Source = source;
        Value = value;
    }
}

public class DocumentRecords : Records
{
    public DocumentRecords(string source, int value)
        : base(ContentTypesString.DocumentNew, source, value) // use here
    {
    }
}

public class HeadlinesRecords : Records
{
    public HeadlinesRecords(string source, int value)
        : base(ContentTypesString.HeadlinesNew, source, value) // use here
    {
    }
}

public static class ContentTypesString
{
    public static string DocumentNew { get { return "Document - New this Month"; } }

    public static string HeadlinesNew { get { return "Headlines - New this Month"; } }
}

【讨论】:

  • 看起来不错 :) 但是在调用者中没有 IF 的情况下,我如何选择制作哪个 Records 子项?
  • 所以一开始,您只有一个类型,并且您想将该类型赋予某些东西,从而创建相应的 Records 子项返回给您?
  • 我添加了一些关于如何创建 Records 实例的代码。我想摆脱在我看来很脏的 Method.Name 并在这种情况下调用正确的 Record 子类构造函数。我有模糊的记忆这是可能的,但我不记得是怎么回事。
  • 我想我发现,我改变了我的程序很多。保存preparedQuery 的静态实用程序方法变成了IQuery 接口的实现,委托已被List 替换,委托调用列表由调用接口方法的list 上的foreach 替换。该接口的实现还包含一个返回所需 Record 子实例的方法。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 2023-04-01
  • 2012-05-09
  • 1970-01-01
  • 2017-07-13
  • 2019-12-26
  • 2021-02-08
  • 2014-10-08
相关资源
最近更新 更多