Java 基于派生数据强制执行子类行为

Java 基于派生数据强制执行子类行为,java,inheritance,Java,Inheritance,我正试图实现一个“Range”类(在Java中)来为它包装的int值提供边界强制功能。我希望它的每个子类都定义自己的最小/最大界限,而不必重写强制这些界限的逻辑。以下是一个例子: public abstract class Range { // I would like each derived class to possess its own distinct instances of the // min/max member data protected stati

我正试图实现一个“Range”类(在Java中)来为它包装的int值提供边界强制功能。我希望它的每个子类都定义自己的最小/最大界限,而不必重写强制这些界限的逻辑。以下是一个例子:

public abstract class Range {
    // I would like each derived class to possess its own distinct instances of the
    // min/max member data
    protected static final int MIN_VAL;
    protected static final int MAX_VAL;

    protected int _value;

    public void set (int newVal) {
        // Range check the input parameter
        // this should use the min/max bounds for the object's most derived class
        if (newVal < MIN_VAL || newVal > MAX_VAL) {
            throw new InvalidParameterException("`newVal` is out of range");
        }

        this._value = newVal;
    }

    public int get() {
        return this._value;
    }
}

// This class should limit its wrapped value to values between 1 and 6 inclusively
public class Die extends Range {
    public Die() {
        MIN_VAL = 1;
        MAX_VAL = 6;
        this.set (1);
    }
}
公共抽象类范围{
//我希望每个派生类都拥有自己的
//最小/最大成员数据
受保护的静态最终整数最小值;
受保护的静态最终整数最大值;
受保护的int_值;
公共无效集(int newVal){
//范围检查输入参数
//这应该使用对象最派生类的最小/最大边界
如果(新值<最小值|新值>最大值){
抛出新的InvalidParameterException('newVal'超出范围”);
}
此值为._值=newVal;
}
公共int get(){
返回此值;
}
}
//此类应将其包装值限制在1和6之间(包括1和6)
公共级模具扩展范围{
公众死亡(){
最小值=1;
最大值=6;
本组(1);
}
}

显然这个实现不起作用,但我如何才能实现我的目标呢?在不重复大部分逻辑的情况下,这是可能的吗?

一种方法是使最小值/最大值实例变量,并让您的子类在构造函数中设置范围:

public abstract class Range {
    // I would like each derived class to possess its own distinct instances of the
    // min/max member data
    protected final int MIN_VAL;
    protected final int MAX_VAL;

    protected int _value;

    protected Range(int min, int max) {
        MIN_VAL = min;
        MAX_VAL = max;
    }

    . . .
}

// This class should limit its wrapped value to values between 1 and 6 inclusively
public class Die extends Range {
    public Die() {
        super(1, 6);
        . . .
    }
}
另一种方法是定义抽象的
checkRange
方法:

public abstract class Range {
    protected int _value;

    public void set (int newVal) {
        checkRange(newVal);
        this._value = newVal;
    }

    public int get() {
        return this._value;
    }

    protected abstract void checkRange(int val) throws InvalidParameterException;
}

// This class should limit its wrapped value to values between 1 and 6 inclusively
public class Die extends Range {
    private final int MIN_VAL = 1;
    private final int MAX_VAL = 6;
    public Die() {
        this.set (1);
    }

    protected void checkRange(int val) throws InvalidParamterException {
        if (newVal < MIN_VAL || newVal > MAX_VAL) {
            throw new InvalidParameterException("`val` is out of range");
        }
    }
}
公共抽象类范围{
受保护的int_值;
公共无效集(int newVal){
校验范围(newVal);
此值为._值=newVal;
}
公共int get(){
返回此值;
}
受保护的抽象无效检查范围(int val)引发InvalidParameterException;
}
//此类应将其包装值限制在1和6之间(包括1和6)
公共级模具扩展范围{
私有最终整数最小值=1;
私人最终整数最大值=6;
公众死亡(){
本组(1);
}
受保护的无效检查范围(int val)引发InvalidParameterException{
如果(新值<最小值|新值>最大值){
抛出新的InvalidParameterException(“val”超出范围);
}
}
}

一种方法是使最小/最大值成为实例变量,并让您的子类在构造函数中设置范围:

public abstract class Range {
    // I would like each derived class to possess its own distinct instances of the
    // min/max member data
    protected final int MIN_VAL;
    protected final int MAX_VAL;

    protected int _value;

    protected Range(int min, int max) {
        MIN_VAL = min;
        MAX_VAL = max;
    }

    . . .
}

// This class should limit its wrapped value to values between 1 and 6 inclusively
public class Die extends Range {
    public Die() {
        super(1, 6);
        . . .
    }
}
另一种方法是定义抽象的
checkRange
方法:

public abstract class Range {
    protected int _value;

    public void set (int newVal) {
        checkRange(newVal);
        this._value = newVal;
    }

    public int get() {
        return this._value;
    }

    protected abstract void checkRange(int val) throws InvalidParameterException;
}

// This class should limit its wrapped value to values between 1 and 6 inclusively
public class Die extends Range {
    private final int MIN_VAL = 1;
    private final int MAX_VAL = 6;
    public Die() {
        this.set (1);
    }

    protected void checkRange(int val) throws InvalidParamterException {
        if (newVal < MIN_VAL || newVal > MAX_VAL) {
            throw new InvalidParameterException("`val` is out of range");
        }
    }
}
公共抽象类范围{
受保护的int_值;
公共无效集(int newVal){
校验范围(newVal);
此值为._值=newVal;
}
公共int get(){
返回此值;
}
受保护的抽象无效检查范围(int val)引发InvalidParameterException;
}
//此类应将其包装值限制在1和6之间(包括1和6)
公共级模具扩展范围{
私有最终整数最小值=1;
私人最终整数最大值=6;
公众死亡(){
本组(1);
}
受保护的无效检查范围(int val)引发InvalidParameterException{
如果(新值<最小值|新值>最大值){
抛出新的InvalidParameterException(“val”超出范围);
}
}
}

最小值和最大值都是常量,因此不能更改它们

添加两个受保护的方法:

protected abstract int getMin();

protected abstract int getMax();
子类实现这些方法,例如:

@Override
protected int getMin() {
   return 7;
}

@Override
protected int getMax() {
   return 67;
}
在你改变的范围内

public void set (int newVal) {
        // Range check the input parameter
        // this should use the min/max bounds for the object's most derived class
        if (newVal < getMin() || newVal > getMax()) {
            throw new InvalidParameterException("`newVal` is out of range");
        }

        this._value = newVal;
    }
公共无效集(int newVal){
//范围检查输入参数
//这应该使用对象最派生类的最小/最大边界
如果(newValgetMax()){
抛出新的InvalidParameterException('newVal'超出范围”);
}
此值为._值=newVal;
}

最小值和最大值都是常量,因此不能更改它们

添加两个受保护的方法:

protected abstract int getMin();

protected abstract int getMax();
子类实现这些方法,例如:

@Override
protected int getMin() {
   return 7;
}

@Override
protected int getMax() {
   return 67;
}
在你改变的范围内

public void set (int newVal) {
        // Range check the input parameter
        // this should use the min/max bounds for the object's most derived class
        if (newVal < getMin() || newVal > getMax()) {
            throw new InvalidParameterException("`newVal` is out of range");
        }

        this._value = newVal;
    }
公共无效集(int newVal){
//范围检查输入参数
//这应该使用对象最派生类的最小/最大边界
如果(newValgetMax()){
抛出新的InvalidParameterException('newVal'超出范围”);
}
此值为._值=newVal;
}

对于第一个实现,由于类中所有值的最小值和最大值都相同,因此最好使用静态数据,而不是为每个实例保留单独的副本,对于第二个实现(抽象检查范围方法),这样做有违目的,因为我必须重复其行为在语义上与所有类型的范围相同的代码。必须为范围的每个子类型重写它违反了DIY原则,不是吗?@weberc2-最好使用静态,但不能重写静态方法。如果您想获得真正的巴洛克风格,您可能可以使用反射仅对声明
MIN_VAL
MAX_VAL
的类的实例应用范围检查。(然后从基类中删除
MIN_VAL
MAX_VAL
)如果希望在子类的实例中检测到这些值的存在,这不是一件小事。关于第二种方法,@asgoth的答案可能是更好的选择。我理解。你的回答确实提供了我最初没有想到的解决方案(这将证明对我可能面临的其他问题很有用,因此再加上一个);但是,考虑到每个子类型的实例数量,我无法证明重复的值是正确的。对于您的第一个实现,由于类中所有值的最小值和最大值都相同,因此最好使用静态数据,而不是为每个实例保留单独的副本,否?关于您的第二个实现(抽象checkRange方法),这种方法有点违背了我要说的目的