【问题标题】:How do I use subclasses in a factory subclass to override abstract class in a superclass factory?如何使用工厂子类中的子类来覆盖超类工厂中的抽象类?
【发布时间】:2018-04-19 17:39:14
【问题描述】:

我正在编写一个程序,它需要对抽象对象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;
    }
}

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

【问题讨论】:

    标签: java subclassing abstract-factory


    【解决方案1】:

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

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

    【讨论】:

    • 您可以将 saveAssignment 抽象为 public abstract boolean saveAssignment(T assignment);,而不是基类中的 public boolean saveAssignment(T assignment) { return false; },这需要派生类提供实现。
    【解决方案2】:

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


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

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

    基类定义了一个带有Assignment 参数的方法。 DCONAssignment is-a 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(&lt;? extends Assignment&gt; 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 &lt;T extends Assignment&gt; 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
        }
    }
    

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2021-06-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2018-04-08
      相关资源
      最近更新 更多