Reputation: 95
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
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
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
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