简体   繁体   English

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

[英]Java: Best practices on how to inherit factory methods from base classes

I'm creating a set of classes to represent various data in a legacy database. 我正在创建一组类来表示遗留数据库中的各种数据。 Instead of using exceptions inside constructors to signal error conditions I've decided to employ factory methods to create my various objects. 我没有在构造函数内部使用异常来表示错误情况,而是决定使用工厂方法来创建各种对象。 However, I'm trying to figure out how best to reuse some of these factories when inheriting from those classes. 但是,我试图找出在继承这些类时如何最好地重用其中一些工厂。 I'm looking for a conceptual explanation (ie: best practices state that you should do ...) not so much an actual code example (although code examples are always welcome). 我正在寻找一个概念性的解释(即:最佳实践表明你应该做......)而不是一个实际的代码示例(尽管代码示例总是受欢迎的)。

For example, let's say I have a class called User with a createUser factory method. 例如,假设我有一个名为User的类,其中包含createUser工厂方法。 I also have another class called Employee that extends the User class. 我还有另一个名为Employee的类,它扩展了User类。 How can I reuse (ie: call) all the code in the createUser method from the createEmployee method so that it populates all of the Employees fields that are inherited from the User class? 如何从createEmployee方法重用(即:调用)createUser方法中的所有代码,以便它填充从User类继承的所有Employees字段?

An obvious "work around" would be to change the Employee class to have a User class instead of extending it, but that doesn't mesh with normal OO principles. 一个明显的“解决方法”是将Employee类更改为具有User类而不是扩展它,但这不符合正常的OO原则。

You can have an additional initializeUser(User user) method, which fills all fields. 您可以使用其他initializeUser(用户用户)方法填充所有字段。 createUser creates a new User and calls initializeUser with it. createUser创建一个新用户并使用它调用initializeUser。 createEmployer creates a new Employer and calls initializeEmployer which calls initializeUser and then adds its Employer stuff. createEmployer创建一个新的Employer并调用initializeEmployer调用initializeUser,然后添加其Employer的东西。

To make it invisible to the outside user, declare both initalize methods protected so they're only visible inside the package. 为了使外部用户看不到它,声明两个initalize方法都受保护,因此它们只在包内可见。 Another design would be to have an own factory class which holds all create and initialize methods. 另一种设计是拥有一个自己的工厂类,它包含所有的创建和初始化方法。

Try to find the best way to model the problem you are doing, and don't get hung up on labeling what you are doing. 尝试找到模拟你正在做的问题的最好方法,不要挂断标记你在做什么。

For example, you want to have two classes, User and Employee, and Employee extends User. 例如,您希望有两个类,User和Employee,以及Employee extends User。

In some class you have getUser and getEmployee. 在某些类中,您有getUser和getEmployee。

In getEmployee you instantiate Employee, then just populate the values for the user. 在getEmployee中,您实例化Employee,然后只填充用户的值。 Here is where I think you are getting stuck on labels. 这是我认为你被卡在标签上的地方。

I would have a DAO (Data Access Object) class, where I put in the logic to actually go to the database. 我会有一个DAO(数据访问对象)类,我在其中放入了实际进入数据库的逻辑。 So, I have a UserDAO and EmployeeDAO. 所以,我有一个UserDAO和EmployeeDAO。

UserDAO only knows how to populate the User object and the same with EmployeeDAO, so EmployeeDAO does something like this: 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;
}

The code snippet helps me organize my thoughts. 代码片段可以帮助我整理自己的想法。 So, you can then either pass in the Employee instantiation and have it be populated from User or you would just copy the values over yourself. 因此,您可以传入Employee实例,并从User填充它,或者只是将值复制到自己身上。

But, this keeps the logic separated and allows you to have a more flexible design. 但是,这可以保持逻辑分离,并使您拥有更灵活的设计。

The way I would do that kind of thing would be something like this. 我会这样做的方式是这样的。 I would create a polymorphic init() method for User and all the specialized subclasses of it, where necessary (for example, your Employee's init() method would only need to call the super-method). 我会在必要时为User及其所有专用子类创建一个多态 init()方法(例如,你的Employee的init()方法只需要调用super方法)。 Then I'd create a separate Factory class that spits out an instance of User (the base class), be it a User or Employee or whatever. 然后我将创建一个单独的Factory类,它会吐出User(基类)的实例,无论是User还是Employee等等。 Inside its createInstance(insert params here) method, I'd create a User or Employee or your specialized instance depending on a parameter, then call the init() method for that instance you've just built. 在其createInstance(insert params here)方法中,我将根据参数创建User或Employee或您的专用实例,然后为您刚刚构建的实例调用init()方法。 That way, you're separating the construction phase from the initialization (since every class should theoretically be able to do its own cooking at init()) and you could inherit the legacy initialization at the instance creation time if that's what you want. 这样,您将构建阶段与初始化分开 (因为理论上每个类都应该能够在init()处进行自己的烹饪)并且您可以在实例创建时继承遗留初始化(如果这是您想要的)。

Some code example: 一些代码示例:

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

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM