Java:从基类继承工厂方法的最佳实践

3
我正在创建一组类来表示遗留数据库中的各种数据。为了避免在构造函数中使用异常来表示错误条件,我决定使用工厂方法来创建我的各种对象。但是,在从这些类继承时,我正在努力找出如何最好地重用其中一些工厂。我正在寻找一个概念性的解释(即:最佳实践规定您应该...),而不是实际的代码示例(尽管代码示例总是受欢迎的)。
例如,假设我有一个名为User的类,其中包含一个createUser工厂方法。我还有一个名为Employee的类,它扩展了User类。如何重用(即调用)createUser方法中的所有代码,以便它填充从User类继承的所有Employee字段?
一个明显的“解决方法”是将Employee类更改为具有User类而不是扩展它,但这与常规OO原则不符。
3个回答

1
你可以有一个额外的 initializeUser(User user) 方法,来填充所有字段。createUser 创建一个新的 User 并调用 initializeUser。createEmployer 创建一个新的 Employer 并调用 initializeEmployer,它调用 initializeUser 然后添加 Employer 的内容。
为使其对外部用户不可见,在类中声明这两个 initialize 方法为 protected,以便只在包内可见。另一种设计方案是拥有一个工厂类,其中保存了所有的 create 和 initialize 方法。

0

尝试找到最好的方式来建模您正在处理的问题,不要纠缠于标记您正在做的事情。

例如,您想要有两个类,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;
}

这段代码片段帮助我整理思路。因此,您可以传递Employee实例化并从User中填充它,或者您可以自己复制值。

但是,这样保持逻辑分离,使您拥有更灵活的设计。


0
我会这样做。我会为User和所有需要的专门子类创建一个多态的init()方法(例如,您的Employee的init()方法只需要调用超级方法)。然后,我会创建一个单独的Factory类,它会生成一个User实例(基类),无论是User还是Employee或其他什么。在其createInstance(插入参数)方法中,我会根据参数创建一个User或Employee或您的特定实例,然后调用刚刚构建的实例的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;
    }
}


我认为这个设计有两个困难:首先,它不允许按照问题中建议的方式创建不同版本。其次,它应该返回你想要创建的类型,这可以通过使用泛型来解决,但使用起来有点麻烦。 - LastFreeNickname
它不需要返回您想要创建的实际类型,因为用户是同一类层次结构的一部分(以User作为父类)。当然,您可以通过自定义init参数来增强此方法。 - webuster
一个createFoo方法应该返回类型为Foo的对象。否则你就必须进行强制类型转换。如果你返回DaddyFoo,那么仍然是正确的,但正如我所说,这样做很麻烦,在某些情况下甚至可能会误导。 - LastFreeNickname

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接