如何在工厂子类中使用子类来覆盖超类工厂中的抽象类?

问题描述 投票:1回答:2

我正在编写一个程序,需要对抽象对象Assignment的子类进行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;
    }
}

总之,抽象工厂处理一些繁重的工作来装载作业。具体工厂处理其Assignment类的特定实现的详细信息。问题是用具体参数覆盖抽象方法。所以问题是,我如何在抽象工厂中指定一个方法并用具体工厂中的具体参数覆盖它?

java subclassing abstract-factory
2个回答
2
投票

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

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

0
投票

JSYK:你不必在getId中覆盖setIdgetNamesetNameDCONAssignment方法。它们从基类继承而来,实际上并没有改变它们。


当您使用@Override时,您告诉编译器您打算使用新方法替换父类中的方法。这意味着您希望父类具有相同名称和签名的方法。如果编译器看起来并且找不到具有相同名称和签名的方法,则会生成错误。 Eclipse会接收错误,检查您的代码,并为您提供有关如何解决问题的建议。

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

基类使用Assignment参数定义方法。一个DCONAssignment是一个Assignment,所以你可以简单地在派生类中定义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);

在这里,您的基类的方法明确声明它将接受任何扩展Assignment的类。您可以在派生类中重写它,并再次检查实际的类以验证它是否被赋予了正确的类。

@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相同,除了方法是否在基类中声明为抽象(无方法体)。


最简单的解决方法是使用选项1方法,使用instanceof检查参数是否实际上是预期类型和强制转换。

更结构化的方法是将工厂类声明为基于模板。

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

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

© www.soinside.com 2019 - 2024. All rights reserved.