我如何在工厂 subclass 中使用 subclasses 来覆盖 superclass 工厂中的抽象 class?

How do I use subclasses in a factory subclass to override abstract class in a superclass factory?

我正在编写一个程序,需要对抽象对象 Assignment 的子 class 执行 CRUD 操作。我有工厂来执行 CRUD 操作,但我在覆盖方法时遇到问题。

public abstract class Assignment {
    protected Integer id = null;
    protected String name = null;
    public Assignment() {}
    public Assignment(Assignment original) { // code here to clone }
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

具体作业

public class DCONAssignment extends Assignment {
    protected Integer amount = null;
    protected String type = null;
    public DCONAssignment() {}
    public DCONAssignment(DCONAssignment original) { // code here to clone }
    public Integer getId() { return id; }
    public void setId(Integer id) { this.id = id; }
    public String getName() { return name; }
    public void setName(String name) { this.name = name; }
}

抽象工厂

public abstract class AssignmentProcessor {
    public abstract Assignment loadAssignment(Integer assignmentId);
//  public abstract boolean saveAssignment(Assignment assignment); // option 1
//  public abstract boolean saveAssignment(<? extends Assignment> assignment); // option 2 // This says "abstract methods do not specify a body"
//  public <T extends Assignment> boolean saveAssignment(T assignment) { //option 3
    public boolean saveAssignment(Assignment assignment) { //option 4
        return false;
    }
    protected Assignment loadAssignment(Integer assignmentId, Class<? extends Assignment> clazz) {
        Assignment assignment = null;
        try {
            assignment = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            e.printStackTrace();
        }
        BurstAssignment burstAssignment = null; // load assignmnet from db
        assignment.setId(burstAssignment.getId());

        return assignment;
    }
}

和混凝土厂

public class DCONAssignmentProcessor extends AssignmentProcessor {
    @Override
    public DCONAssignment loadAssignment(Integer assignmentId) {
        DCONAssignment assignment = (DCONAssignment) loadAssignment(assignmentId, DCONAssignment.class);
        return assignment;
    }
    @Override
    public boolean saveAssignment(DCONAssignment assignment) { // eclipse says I need to override a method with options 1, 3 and 4
        return false;
    }
}

总而言之,抽象工厂处理加载作业的一些繁重工作。具体工厂处理它们特定的分配实现的细节class。问题是用具体参数覆盖抽象方法。那么问题来了,如何在抽象工厂中指定方法,在具体工厂中用具体的参数覆盖呢?

我解决了这个问题,解决方案是使抽象工厂通用

public abstract class AssignmentProcessor<T extends Assignment>  {
    public abstract T loadAssignment(Integer assignmentId);
    public boolean saveAssignment(T assignment) {
        return false;
    }
    protected Assignment loadAssignment(Integer assignmentId, Class<T> clazz) {
        Assignment assignment = null;
        try {
            assignment = clazz.newInstance();
        } catch (InstantiationException | IllegalAccessException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        BurstAssignment burstAssignment = SessionHelper.getSession().getBurstAssignment(assignmentId);
        assignment.setId(burstAssignment.getId());
        return assignment;
    }
}

混凝土厂

public class DarfAssignmentProcessor extends AssignmentProcessor<DarfAssignment> {
    @Override
    public DarfAssignment loadAssignment(Integer assignmentId) {
        DarfAssignment assignment = (DarfAssignment) loadAssignment(assignmentId, DarfAssignment.class);
        return assignment;
    }
    @Override
    public boolean saveAssignment(DarfAssignment assignment) {
        return false;
    }
}

JSYK:您不必覆盖 DCONAssignment 中的 getIdsetIdgetNamesetName 方法。它们是从基础 class 继承而来的,您实际上并没有改变它们。


当您使用 @Override 时,您是在告诉编译器您 打算 您正在创建的方法将父 class 中的方法替换为新方法。这意味着您 期望 父 class 有一个具有相同名称和签名的方法。如果编译器查找但找不到具有相同名称和签名的方法,则会生成错误。 Eclipse 接受错误,检查您的代码,并为您提供有关如何解决问题的建议。

选项 1:public abstract boolean saveAssignment(Assignment assignment);

基础 class 定义了一个带有 Assignment 参数的方法。一个DCONAssignment是-一个Assignment,所以你可以简单地在派生的class中定义saveAssignment方法来接受一个Assignment,并传入DCONAssignment对象。

要正常运行,您必须在派生方法中强制转换:

@Override
public boolean saveAssignment(Assignment assignment) {
    if (assignment instanceof DCONAssignment)) {
        DCONAssignment da = (DCONAssignment) assignment;
        // ... save da 
        return true;
    } else {
        throw new IllegalArgumentException("Expected DCONAssignment");
    }
}

选项 2:public abstract boolean saveAssignment(<? extends Assignment> assignment);

在这里,您的基础 class 方法明确声明它将接受任何扩展 Assignment 的 class。您将在派生的 class 中覆盖它,并再次检查实际的 class 以验证它被赋予正确的 class.

@Override
public boolean saveAssignment(<? extends Assignment> assignment) {
    if (assignment instanceof DCONAssignment) {
        DCONAssignment da = (DCONAssignment) assignment;
        // ... save da 
        return true;
    } else {
        throw new IllegalArgumentException("Expected DCONAssignment");
    }
}

选项 3:public <T extends Assignment> boolean saveAssignment(T assignment)

同样,这与选项 2 相同,但明确为模板类型指定名称 T

选项 4:看起来与选项 1 相同,除了方法是否在基础中声明为抽象(无方法体)class。


最简单的修复方法是使用选项 1 方法,使用 instanceof 检查参数是否确实是预期的类型,然后进行转换。

一种更结构化的方法是声明您的工厂 class 是基于模板的。

public abstract class AssignmentProcessor<T extends Assignment> {
    public abstract T loadAssignment(Integer assignmentId);
    public abstract boolean saveAssignment(T assignment);
}

然后您可以使用预期类型声明您的派生处理器:

public class DCONAssignmentProcessor extends AssignmentProcessor<DCONAssignment> {
    @Override
    public DCONAssignment loadAssignment(Integer assignmentId) {
        // Your load code
    }
    @Override
    public boolean saveAssignment(DCONAssignment assignment) {
        // Your save code
    }
}

抽象工厂可以像以前一样实现任何常用方法来完成繁重的工作。