【问题标题】:Factory design pattern; parent = new child()工厂设计模式;父母=新孩子()
【发布时间】:2017-05-24 05:18:17
【问题描述】:

当我使用工厂模式时,当孩子有额外的属性/方法时,我对如何从中创建子类感到困惑。工厂返回父类型,因为它确定要制作哪个子类,但是当发生这种情况时,我不能像子类一样使用它返回的内容。

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

所以我的问题是,当我创建一个 PersonFactory 对象并决定使用该工厂来创建其他派生类时。我注意到 getPerson() 返回 Person 而不是实际输入 Admin 或 Customer。如何让工厂创建子类,以便它们实际上是子对象?

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

【问题讨论】:

  • 看看这段代码,我想知道管理员是否真的应该“成为”一个人——也许它应该是一个人的“角色”。我意识到这段代码可能来自教程或其他东西,但如果它是生产代码,我会考虑 Liskov 替换原则并考虑这是否违反它。 en.wikipedia.org/wiki/Liskov_substitution_principle

标签: c# design-patterns factory


【解决方案1】:

快速修复是这样的

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

但更好的实现是

1) 为您的工厂类使用静态方法。

2) 使用泛型和接口。

您的新代码将是:

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

以及如何使用:

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

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

【讨论】:

    【解决方案2】:

    您无法访问该属性的原因是因为您希望这行代码的返回类型为Person

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

    Person 不包含SecurityRole 的定义。因为您将返回类型定义为Person,所以您的结果实际上被转换回Person 对象而不是Admin 对象。

    您应该可以通过以下方式解决此问题:

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

    或使用:

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

    【讨论】:

    • var admin = pf.getPerson("admin");有效,但我仍然无法访问子属性/方法
    【解决方案3】:

    由于 .id 有效,但 .SecurityRole 无效,我认为可以肯定地说您创建的是 Person 而不是 Admin。

    尝试Admin admin = pf.getPerson("admin"); 而不是Person admin = pf.getPerson("admin");

    【讨论】:

    • 管理员 admin = pf.getPerson("admin");似乎不起作用,无法将 Person 隐式转换为 Admin。我认为该方法想要返回一个人。
    • Person admin = new Person; 怎么样? -- 管理员 realAdmin = admin.getPerson("admin");虽然在这一点上应该首先质疑这是否是正确的设计模式。
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2023-03-25
    • 1970-01-01
    • 1970-01-01
    • 2011-11-20
    • 2010-09-06
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多