【问题标题】:Facade a class without writing lots of boilerplate code?在不编写大量样板代码的情况下外观类?
【发布时间】:2013-06-29 15:05:52
【问题描述】:

假设我有一个来自第 3 方的类,它是一个数据模型。它可能有 100 个属性(一些具有公共设置器和获取器,其他具有公共获取器但私有设置器)。我们将这个类称为 ContosoEmployeeModel

我想用一个接口(INavigationItem,它具有 Name 和 DBID 属性)来装饰这个类,以允许它在我的应用程序中使用(它是一个 PowerShell 提供程序,但现在这并不重要)。但是,它还需要可用作 ContosoEmployeeModel。

我的初始实现如下所示:

public class ContosoEmployeeModel
{
    // Note this class is not under my control. I'm supplied
    // an instance of it that I have to work with.

    public DateTime EmployeeDateOfBirth { get; set; }
    // and 99 other properties.
}

public class FacadedEmployeeModel : ContosoEmployeeModel, INavigationItem
{
    private ContosoEmployeeModel model;
    public FacadedEmployeeModel(ContosoEmployeeModel model)
    {
        this.model = model;
    }

    // INavigationItem properties
    string INavigationItem.Name { get; set;}

    int INavigationItem.DBID { get; set;}

    // ContosoEmployeeModel properties
    public DateTime EmployeeDateOfBirth
    {
        get { return this.model.EmployeeDateOfBirth; }
        set { this.model.EmployeeDateOfBirth = value; }
    }
    // And now write 99 more properties that look like this :-(
}

但是,很明显,这将涉及编写大量样板代码来公开所有属性,如果可以的话,我宁愿避免这样做。我可以在部分类中 T4 代码生成此代码,如果没有更好的想法,我会这样做,但我想在这里问是否有人使用一些 super wizzy @ 有更好的想法C#魔法之987654323@

请注意 - 我用来获取 ContosoEmployeeModel 的 API 只能返回一个 ContosoEmployeeModel - 我不能扩展它来返回一个 FacededEmployeeModel,所以包装模型是我能想到的唯一解决方案 - 我很高兴成为不过更正了:)

【问题讨论】:

  • 使用AutoMapper怎么样?
  • 我很困惑 - 你从 ContosoEmployeeModel 继承你的外观类 并且 你有一个 ContosoEmployeeModel 通过合成嵌入到你的外观中?为什么?
  • @MatthewWatson Oooh - 我从没听说过。这看起来很有希望 - 我会尝试并回帖
  • @RB。 :在这种情况下,Resharper 的委派成员功能就是您要寻找的机器人。 jetbrains.com/resharper/webhelp/… ... 非常适合生成外墙/代理。

标签: c# design-patterns adapter .net-4.5 facade


【解决方案1】:

另一种可能适合您的方法是使用 AutoMapper 将基类映射到您的外观这里是示例代码:

class Program
    {
        static void Main(string[] args)
        {
            var model = new Model { Count = 123, Date = DateTime.Now, Name = "Some name" };

            Mapper.CreateMap<Model, FacadeForModel>();
            var mappedObject = AutoMapper.Mapper.Map<FacadeForModel>(model);

            Console.WriteLine(mappedObject);

            Console.ReadLine();
        }

        class Model
        {
            public string Name { get; set; }

            public DateTime Date { get; set; }

            public int Count { get; set; }
        }

        interface INavigationItem
        {
            int Id { get; set; }

            string OtherProp { get; set; }
        }

        class FacadeForModel : Model, INavigationItem
        {
            public int Id { get; set; }

            public string OtherProp { get; set; }
        }
    }

【讨论】:

  • 不幸的是,这对我不起作用 - 我需要 FacadedEmployeeModel 的所有 100 个属性的值与 ContosoEmployeeModel 相同。
  • 你用 FacadedEmployeeModel 做什么?
  • 从 API 中检索 Contoso 模型。但是,我需要将其作为 INavigationItem 进行操作。因此,外观会将 Contoso 模型转换为 INavigationItem。
  • 使用 AutoMapper,您将使用来自 ContosoEmployeeModel 的所有数据填充 Facade,因此您可以同时将其用作 INavigationItem 和 ContosoEmployeeModel,而无需重新声明所有模型属性
  • 你是对的!我不敢相信我错过了这一点! @MatthewWatson 建议使用 Automapper,但我显然太快放弃了它。令人沮丧的是,我需要调查 Contoso 模型中的一个错误(属性可以初始化为 null,但不能设置为 null),但 AutoMapper 绝对是正确的答案。
【解决方案2】:

Resharper 允许创建“委托成员”,它将包含对象的接口复制到包含对象上,并将方法调用/属性访问通过隧道传递到包含对象。

http://www.jetbrains.com/resharper/webhelp/Code_Generation__Delegating_Members.html

完成此操作后,您就可以在代理类上提取一个接口。

【讨论】:

  • 我刚刚下载了免费试用版,这肯定对我有用 :) 奇怪的是,它不会使用“new”关键字创建它们,这很遗憾,所以我会无论如何都必须手动编辑它(但显然要快得多!!)。我想我还是会使用 T4 来完成,因为如果 Contoso 模型发生变化,生成新版本会更容易,但非常感谢您的建议。
猜你喜欢
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2016-04-09
  • 2016-04-02
  • 2017-10-26
相关资源
最近更新 更多