【问题标题】:Java: Best practices on how to inherit factory methods from base classesJava:如何从基类继承工厂方法的最佳实践
【发布时间】:2014-02-04 15:24:04
【问题描述】:

我正在创建一组类来表示旧数据库中的各种数据。我决定使用工厂方法来创建各种对象,而不是在构造函数中使用异常来指示错误情况。但是,我试图弄清楚从这些类继承时如何最好地重用其中一些工厂。我正在寻找一个概念性的解释(即:最佳实践说明你应该这样做......)而不是实际的代码示例(尽管代码示例总是受欢迎的)。

例如,假设我有一个名为 User 的类,它有一个 createUser 工厂方法。我还有另一个名为 Employee 的类,它扩展了 User 类。如何从 createEmployee 方法重用(即:调用)createUser 方法中的所有代码,以便填充从 User 类继承的所有员工字段?

一个明显的“解决方法”是将 Employee 类更改为拥有一个 User 类而不是扩展它,但这不符合正常的 OO 原则。

【问题讨论】:

    标签: java inheritance parent-child factory-pattern


    【解决方案1】:

    您可以有一个额外的 initializeUser(User user) 方法,它填充所有字段。 createUser 创建一个新用户并用它调用 initializeUser。 createEmployer 创建一个新的 Employer 并调用 initializeEmployer 调用 initializeUser 然后添加它的 Employer 东西。

    要使其对外部用户不可见,请声明两个 initalize 方法受保护,以便它们仅在包内可见。另一种设计是拥有一个包含所有创建和初始化方法的自己的工厂类。

    【讨论】:

      【解决方案2】:

      试着找到最好的方法来模拟你正在做的问题,不要拘泥于给你正在做的事情贴标签。

      例如,您希望有两个类,User 和 Employee,而 Employee 扩展了 User。

      在某些类中,您有 getUser 和 getEmployee。

      在 getEmployee 中实例化 Employee,然后为用户填充值。这就是我认为你被标签卡住的地方。

      我将有一个 DAO(数据访问对象)类,我在其中放入逻辑以实际访问数据库。所以,我有一个 UserDAO 和 EmployeeDAO。

      UserDAO 只知道如何填充 User 对象,而 EmployeeDAO 也是如此,所以 EmployeeDAO 做了这样的事情:

      Employee getEmployee(String id) {
        Employee emp = new Employee();
        User u = UserDAO.getUser(id);
        // either populate values or pass in the Employee since it can be a User class, to be populated.
        // get employee values
        return emp;
      }
      

      代码 sn-p 帮助我整理思绪。因此,您可以传入 Employee 实例化并从 User 填充它,或者您只需将值复制到自己身上。

      但是,这会保持逻辑分离并允许您进行更灵活的设计。

      【讨论】:

        【解决方案3】:

        我会做这种事情的方式是这样的。我会在必要时为 User 及其所有专用子类创建一个 多态 init() 方法(例如,您的 Employee 的 init() 方法只需要调用超方法)。然后,我将创建一个单独的 Factory 类,该类会生成一个 User 实例(基类),可以是 User 或 Employee 或其他。在其 createInstance(insert params here) 方法中,我将根据参数创建一个用户或雇员或您的专用实例,然后为您刚刚构建的该实例调用init() 方法。 这样,您将构造阶段与初始化分开(因为理论上每个类都应该能够在 init() 中进行自己的烹饪),并且您可以在实例创建时继承旧的初始化如果这就是你想要的。

        一些代码示例:

        class User() {
            //... your fields and constructor here
        
            public void init() {
               //... do your User init here
            }
        }
        
        class Employee extends User {
            ...
            public void init() {
               super.init();
               // ... other init stuff if you want
            }
        }
        
        class UserFactory{
            // ...
        
            public User createInstance(UserType type, String name, ...) {
                User user;
                switch (type) {
                    case UserType.EMPLOYEE: user = new Employee(name,...);
                //... your other cases here
                }
        
                // the important part
                user.init();
                return user;
            }
        }
        

        【讨论】:

        • 我认为这种设计有两个困难:首先,它现在允许问题中建议的不同创建版本。其次它应该返回你想要创建的类型,这可以通过使用泛型来解决,但是使用起来有点麻烦。
        • 它不需要返回你想要创建的实际类型,因为用户是同一个类层次结构的一部分(用户作为爸爸)。这个方法当然可以通过你可以传递给它的自定义初始化参数来增强。
        • createFoo 方法应返回 Foo 类型。否则你将不得不施放它。如果您返回 DaddyFoo,您仍然是正确的,但正如我所说,这很麻烦,在某些情况下甚至可能会产生误导。
        猜你喜欢
        • 2013-02-06
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2014-11-07
        • 2021-06-24
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多