Java 基于派生数据强制执行子类行为
我正试图实现一个“Range”类(在Java中)来为它包装的int值提供边界强制功能。我希望它的每个子类都定义自己的最小/最大界限,而不必重写强制这些界限的逻辑。以下是一个例子: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
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方法),这种方法有点违背了我要说的目的