K. Sunki
K. Sunki

Reputation: 95

Factory design pattern; parent = new child()

When I'm using the factory pattern, I'm confused with how to make child classes from it when the child has extra properties/methods. The factory returns the parent type as it works out which child to make but when this happens I can't use what it returns like a child class.

public abstract class Factory 
{
        public abstract Person getPerson(string type);
}

public class PersonFactory : Factory
{
        public override Person getPerson(string type) {
               switch (type) {
                      case "admin": 
                             return new Admin();
                      case "customer": 
                             return new Customer();
                      default: 
                             return new Admin();
               }
        }
}


public abstract class Person
{
        public abstract string Type { get; }
        private int _id;

        public int Id
        {
            get { return _id; }
            set { _id = value; }
        }
}

public class Admin : Person
{
        private string _securityRole;

        public Admin()
        {
            Id = 0;
        }

        public override string Type
        {
            get{
                return "admin";
            }
        }

        public string SecurityRole
        {
            get { return _securityRole; }
            set { _securityRole = value; }
        }
}

So my question is, when I create a PersonFactory object and decide to use that factory to create other derived classes. I noticed that getPerson() returns Person and not actually type Admin or Customer. How can I make the factory create the child classes so that they are actually child objects?

Factory pf = new PersonFactory();
Person admin = pf.getPerson("admin");
admin.Id = 1;            // is fine
admin.SecurityRole       // cannot access

Upvotes: 0

Views: 1919

Answers (3)

hvojdani
hvojdani

Reputation: 470

quick fix is this

Admin admin = (Admin)pf.getPerson("admin");

but better implementation is

1) use static method for your factory class.

2) use generic and interface.

your new code will be:

 public class PersonFactory //: Factory
    {
        public static T getPerson<T>() where T: IPerson
        {
            return Activator.CreateInstance<T>();
        }
    }


    public interface IPerson
    {
        string Type { get; }
        int Id { get; set; }        
    }

    public class Admin : IPerson
    {
        private string _securityRole;

        public Admin()
        {
            Id = 0;
        }

        public string Type
        {
            get
            {
                return "admin";
            }
        }

        public string SecurityRole
        {
            get { return _securityRole; }
            set { _securityRole = value; }
        }

        public int Id
        {
            get;set;
        }
    }

    public class Customer : IPerson
    {
        private string _securityRole;

        public Customer()
        {
            Id = 0;
        }

        public string Type
        {
            get
            {
                return "customer";
            }
        }

        public string SecurityRole
        {
            get { return _securityRole; }
            set { _securityRole = value; }
        }

        public int Id
        {
            get;set;
        }
    }

and how to use:

 Admin a = PersonFactory.getPerson<Admin>();

 Customer b = PersonFactory.getPerson<Customer>();

Upvotes: 2

MarionPearson
MarionPearson

Reputation: 74

Since .id is working but not .SecurityRole I think it's safe to say that you made a Person and not an Admin.

Try Admin admin = pf.getPerson("admin"); instead of Person admin = pf.getPerson("admin");

Upvotes: 0

JanR
JanR

Reputation: 6132

The reason you cannot access the property is because you are expecting a return type of Person for this line of code:

Person admin = pf.getPerson("admin");

Person does not contain a definition of SecurityRole. Because you are defining the return type to be Person your result is effectively cast back to a Person object not an Admin object.

You should be able to fix this by going:

var admin = pf.getPerson("admin");

or by using:

Admin admin = pf.getPerson("admin");

Upvotes: 0

Related Questions