【问题标题】:What Design Pattern can I use to accomplish the following我可以使用什么设计模式来完成以下任务
【发布时间】:2014-08-18 05:09:35
【问题描述】:

在我的代码中,我希望能够“构建”这样的对象..

// Build a Person instance and add types that the person is
Person person = new Person(); 
person = new Leader(person);
person = new Secretary(person);
person = new Parent(person);

上述代码的目标是构建一个添加了多种类型的基础对象——领导者、秘书和父对象。具体来说,我的目标是能够构建一个基础对象(Person)并使该对象能够同时采用多种类型,以便以下条件返回 true:

(((人是领导) && (人是秘书) && (人是家长))

是否有我可以使用的设计模式来完成此任务?

上述示例的问题在于,person 对象一次只能是一个子类型,并且所有之前的实例显然都被覆盖了。换句话说,唯一会返回 true 的条件是 (person is Parent),因为它是最后一行。

注意:我最初认为装饰器模式听起来就像我需要的那样,但从我的阅读中,装饰器模式似乎更多的是关于将行为添加到对象与扩展其类型相反。

更新

为了清楚起见 - 我想我应该在我的 OP 中提到我正在尝试使用我的类创建一个反映我的 RDBM 设计的设计。

所以,继续原来的例子 -

我的 RDBM 包含表 Person、Leader、Secretary 和 Parent。 Person 表具有 PersonId PK,其他表具有 PersonId FK

当我执行一个连接所有表的查询时,我可以确定哪些 Person 记录在子表中具有非空 FK。

展平后,查询结果可能如下所示:

PersonId | FirstName | LeaderId | LeaderApproved | SecretaryId | SecretaryFavPencil | ParentId  
----------------------------------------------------------------------------------------------
100      | Frank     | 34       | True           | Null        | Null               | 700
----------------------------------------------------------------------------------------------
743      | Dweezil   | 43       | False          | 343         | Ticon              | 654
----------------------------------------------------------------------------------------------
567      | Ahmet     | Null     | Null           | Null        | Null               | 123
----------------------------------------------------------------------------------------------

上面的结果表向我们展示了弗兰克是领导者和家长; Dweezil 是领导者、秘书和家长,Ahmet 只是家长。

在我的数据访问层中,我使用一个查询来检索所有 Person 记录及其关联的 FK 表,实例化 Person 对象,然后将 List 返回给调用者。

然后,调用者可以对 Person 对象做任何他需要做的事情,但他可以通过 (person is Leader) 检查 Person 对象的所有类型。

【问题讨论】:

  • 在我看来,这正是工厂模式的设计目的。当然,除非我错过了图片中的某些内容。
  • @Leron OP 不希望每个任务都有一个“新”人,但他想为现有人分配一个新角色。这就像多重继承。在基本类型的人背后隐藏着一个可以承担不同角色的精致对象。哦,显然继承关系是在运行时动态建立的。
  • 如果两种类型有相同的方法怎么办?你应该包括你打算如何使用它。如果只是添加类型而不是不同的行为,请使用标志枚举。如果要添加行为,则可以改用组合(例如,使用 Builder 设计模式)。

标签: c# design-patterns decorator


【解决方案1】:

我认为Strategy 模式应该适合您的需求。
您的问题并未指定您的所有要求,但您可以拥有一个由 Secretary LeaderParent 等类型组合而成的对象,然后在运行时您必须选择其中哪一个是目前选择的策略。

另外,假设所有类型都有某种通用接口,组合对象也将实现该接口,您可以将实例保存在数组中,例如:

IPerson[] _rolles  = 
                 new IPerson[]{new Leader(this), new Secretary(this), new Parent(this)};

并且有一个类型检查的方法,看起来像这样:

        public bool Is(Type type)
        {
            return this.Is(new Type[]{type});
        }

        public bool Is(Type[] types)
        {
            bool isType = true;
            foreach (var type in types)
            {
                isType &= this._rolles.Any(r => r.GetType() == type);
            }
            return isType;
        }

编辑:

更完整的代码示例:

    public class Person : IPerson
    {

        List<IPerson> _rolles;
        IPerson _chosenStrategy;


        public Person()
        {
            this._rolles =
                new List<IPerson>() { new Leader(this), new Secretary(this), new Parent(this) };
            this._chosenStrategy = this._rolles[0];
        }

        public void AddRole(Func<Person, IPerson> creator) {
              IPerson newRole = creator(this)
              //You can choose to remove duplicate roles by uncommenting the following line:
              //this.RemoveRole(newRole.GetType());
              this._rolles.Add(newRole);
        }

        public void RemoveRole(Type type) {
              this._rolles.RemoveAll(r => r.GetType() == type);
        }


         public bool Is(Type type)
        {
            return this.Is(new Type[]{type});
        }

        public bool Is(Type[] types)
        {
            bool isType = true;
            foreach (var type in types)
            {
                isType &= this._rolles.Any(r => r.GetType() == type);
            }
            return isType;
        }

        private void SetStrategy(Type type)
        {
            this._chosenStrategy = this._rolles.Where(r => r.GetType() == type).FirstOrDefault();
        }

        /*Rest of Implementation goes here*/
    }

以及其他必需的类:

    interface IPerson
    {
        /*Implementation goes here*/
    }
    class Leader : IPerson
    {
        public Leader(IPerson p)
        {

        }
        /*Rest of Implementation goes here*/
    }

    class Parent : IPerson
    {
        public Parent(IPerson p)
        {

        }
    }

    class Secretary : IPerson
    {
        public Secretary(IPerson p)
        {

        }
        /*Rest of Implementation goes here*/
    }

【讨论】:

  • 但是对于“同时使用多种类型”的要求,这会失败。
【解决方案2】:

(((人是领导) && (人是秘书) && (人是家长))

从技术上讲,这是可能的,但前提是领导者是其他两个之一,并且其他两个中的一个始终是其他两个之一。

public Leader : Person { }
public Secretary : Leader { }
public Parent : Secretary/Leader { }

如果不是总是这种情况,那么您的特定请求是不可能使用该特定代码的。

如果您不喜欢使用is,那么您也可以使用接口:

(((person is ILeader) && (person is ISecretary) && (person is IParent))

public inteface IPerson;
public inteface ILeader : IPerson;
public interface ISecretary : IPerson;
public interface IParent : IPerson;

public Leader : ILeader;
public Secretary : ISecretary;
public Parent : IParent;

public LeaderSecretary : ILeader, ISecretary;
public LeaderParent : ILeader, IParent;
public SecretaryParent: ISecretary, IParent,
public LeaderSecretaryParent: ILeader, ISecretary, IParent;

但是说真的不要这样做。

【讨论】:

    【解决方案3】:

    首先。 OOP 中的类主要用于表达行为。您说“似乎更多的是向对象添加行为”意味着您的类与行为无关。如果不是,那它们是关于什么的?

    ((person is Leader) && (person is Secretary) && (person is Parent))
    

    OOP 中的类型用于编译器。使用类型作为程序逻辑的一部分在 OOP 编程中被认为是错误的做法。此外,遵循此代码显然是一种行为。因此,与其试图弄乱类型,不如总结你的要求并找出一个确实满足你要求的设计。在您的情况下,第一个要求是能够在运行时更改一个人的“角色”。如果这不改变行为,简单的Enum 就足够了。如果有行为,那么Strategy,也许结合Composite是可能的。第二个要求是有行为,只有当一个人有多个角色时才会执行。如果您使用的是枚举,那么它很简单。但是当你使用策略时它变得更加复杂。虽然我没有确切的解决方案,但我认为如果你要进行类型检查,那么它应该被封装在某种“工厂”中,根据人和他的角色创建行为。

    【讨论】:

    • @"adding behavior" - 我的意思是“添加 method 功能”。换句话说,装饰器模式是一种设计,其中一个对象具有一个特定方法的外观,但是当调用该方法时,将调用子类的覆盖。 - 我将术语行为等同于方法。我感兴趣的是扩展类的 fields (而不是方法)。也就是说,我承认我可能误解了装饰器模式的定义。
    【解决方案4】:

    我认为你需要的是装饰器模式,你可以使用工厂和策略来帮助你。hope this can give you an idea

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2014-09-22
      • 1970-01-01
      • 1970-01-01
      • 2011-08-13
      • 1970-01-01
      • 2016-08-23
      • 1970-01-01
      • 2015-10-23
      相关资源
      最近更新 更多