我可以使用什么设计模式来完成以下操作

时间:2014-08-18 05:09:35

标签: c# design-patterns decorator

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

// 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);

上面代码的目标是构建一个添加了多个类型的基础对象 - Leader,Secretary和Parent。具体来说,我的目标是能够构建一个基础对象(Person)并使该对象能够同时处理多个类型,以便以下条件返回true:

<(>(人是领袖)&amp;&amp;(人是秘书)&amp;&amp;(person is Parent))&lt;&lt;&lt; - 返回True

我可以使用设计模式来实现这一目标吗?

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

注意:我最初认为Decorator Pattern 听起来像我需要的那样但是根据我的阅读,Decorator模式似乎更多的是将行为添加到对象同意延长其类型。

更新

为了清楚起见 - 我想我应该在我的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
----------------------------------------------------------------------------------------------

上面的结果表告诉我们Frank是领导者和父母; Dweezil是领导者,秘书和父母,Ahmet只是父母。

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

然后调用者可以执行他需要对Person对象执行的任何操作,但是他能够通过(person is Leader)检查Person对象的所有类型。

4 个答案:

答案 0 :(得分:4)

我认为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*/
    }

答案 1 :(得分:2)

  <(>(人是领袖)&amp;&amp;(人是秘书)&amp;&amp;(person is Parent))&lt;&lt;&lt; - 返回True

从技术上讲,这是可能的,但前提是领导者是另外两个中的一个,而另外两个中的一个总是其中一个。

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

如果这不是总是这种情况,那么使用该特定代码就无法提出具体请求。

如果您使用is设置了死机,那么您也可以使用接口:

  

((人是ILeader)&amp;&amp;(人是ISecretary)&amp;&amp;(人是IParent))&lt;&lt;&lt;&lt; - 返回True

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;

严重不这样做。

答案 2 :(得分:1)

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

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

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

答案 3 :(得分:1)

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