Which design pattern can be used to accomplish the following

In my code, I would like to be able to "construct" such an object.

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

      

The purpose of the above code is to create a base object with several types added to it - leader, secretary, and parent. In particular, my goal is to create a base object (Person) and make this object capable of accepting multiple types at the same time so that the following condition returns true:

((person is the leader) && (person is the secretary) && (person is the parent)) <<<- Returns True

Is there a design pattern I can use for this?

The problem with the examples above is that the person object can only be one subtype at a time and all previous instances appear to be overwritten. In other words, the only condition that returns true is (person is Parent)

because it is the last in the line.

Note. I originally thought the Decorator Pattern was similar to what I needed, but from what I read, the Pattern Decorator seems to have more to do with adding behavior to an object that has been added to an extension of its type.

Update

For clarity - I suppose I should have mentioned in my OP that I am trying to create a design with my classes that mirrors the design of my RDBM.

So, continuing with the original example -

My RDBM contains Person, Leader, Secretary and Parent tables. Person table has PersonId PK

, and others have PersonId FK

.

When I run a query that joins all the tables, I can determine which Person records contain non-zero FKs in the sub tables.

The smoothed query result might look like this:

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
----------------------------------------------------------------------------------------------

      

The above table shows that Frank is Leader and Parent; Dwaisil is a leader, secretary and parent, Ahmet is just a parent.

In my data access layer, I use a single query to retrieve all Person records along with their associated FK'd tables, instantiate Person objects, and then return the list to the caller.

The caller can then do whatever he wants with the Person objects, but he can check all types of Person objects with (person is Leader)

.

+3


source to share


4 answers


Firstly. Classes in OOP are primarily designed to express behavior. You say "looks like more about adding behavior to an object" means that your classes are not about behavior. If not, what are they talking about?

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

      



OOP types are for the compiler. Using a type as part of programming logic is considered a bad practice in OOP programming. Also, the behavior is clear after this code. So, instead of trying to mess with types, you should summarize your requirements and figure out a design that suits your requirements. In your case, the first requirement is the ability to change the "role" of a person at runtime. If that doesn't change the behavior, simple enough Enum

. If there is behavior, then Strategyperhaps combined with Composite is possible. The second requirement has behavior that is only fulfilled when the person has multiple roles. If you are using an enumeration, then it's easy. But when using a strategy, it becomes more complex. While I don't have an exact solution, I think that if you have type checking then it should be encapsulated inside some kind of "factory" that creates behavior based on the person and their roles.

+1


source


I think the Strategy pattern should suit your needs.
Your question doesn't list all of your requirements, but you can have an object that is composite of types such as Secretary

Leader

and Parent

, then at runtime you will have to choose which one is the chosen strategy at the moment.

Also, assuming that all types have some kind of common interface that the linked object will implement, you can store the instances in an array, for example:

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

      

And you have a type checking method that looks something like 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;
        }

      




Edit:

An example of more complete code:

    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*/
    }

      

And other required classes:

    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*/
    }

      

+4


source


((person is the leader) && (person is the secretary) && (person is the parent)) <<<- Returns True

Technically, this is possible, but only if the Leader is one of the other two, and one of the other two is always one of the others.

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

      

If this is not always the case, then your specific request is not possible using that specific code.

If you are dead using is

then alternatively you can use interfaces:

((person is ILeader) && (person is ISecretary) && (person is IParent)) <<<- Returns 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;

      

But seriously, don't do it.

+2


source


I think you want the Decorator pattern and you can use factory and strategy to help you. hope this can give you an idea

+1


source







All Articles