Java 支持实现接口的泛型类的静态函数的最佳设计模式

Java 支持实现接口的泛型类的静态函数的最佳设计模式,java,generics,design-patterns,interface,Java,Generics,Design Patterns,Interface,我有一个界面操作: public interface Operations{ Operations add(Operations op); Operations subtract(Operations op); } 此界面应允许用户选择如何进行简单计算。例如,如果用户只想使用数据类型Integer及其基本操作,则可以使用类MyInteger: // simple implementation without type check etc.. public final cla

我有一个界面
操作

public interface Operations{

    Operations add(Operations op);

    Operations subtract(Operations op);
}
此界面应允许用户选择如何进行简单计算。例如,如果用户只想使用数据类型
Integer
及其基本操作,则可以使用类
MyInteger

// simple implementation without type check etc..
public final class MyInteger implements Operations{
    private final int delegate;

    public MyInteger(int i){
        delegate = i;
    }

    @Override
    Operations add(Operations other){
        return new MyInteger(delegate + ((MyInteger) other).delegate);
    }
    @Override
    Operations subtract(Operations other){
        return new MyInteger(delegate - ((MyInteger) other).delegate);
    }
    (...)
}
在其他类中,将根据接口
操作
的功能进行计算。但有时我需要一个静态上下文,比如
valueOf(val)
函数,它为给定字符串、double、int等返回相应类的实现,如本例所示:

public class Calculation<D extends Operations> {

    private final D value1, value2;
    private final D value3 = D.valueOf(4);  // cannot implement this in interface 

    public Calculation(D value1, D value2){
        this.value1 =value1;
        this.value2 = value2;
    }

    public D sumPlusValue3(){
        return value1.plus(value2).plus(value3);
    }
}
但是,在研究了这些模式之后,我也找不到一种干净的方法来实现
Calculation
类中
value3
的泛型类
D

编辑1

我编辑了这个问题并标记了@Stefan Haustein的答案,因为这是解决我问题的最佳方法。
但是@davidxxx的回答也是关于我最初的问题的一个很好的答案-如何仅表示一个
valueOf(int-val)
函数。

如果在
计算中
附近总是有一个
D
的实例,您只需将
valueOf
设置为
操作的非静态成员
,尽管技术上不需要相应的值

如果对
valueOf
使用“虚拟”实例不是一个选项,则可以要求
Class
作为
计算的构造函数参数。这将允许您调用
newInstance()
,可能提供了一个中性元素——但是您仍然需要一个操作,例如
addInt
,以获得具体的值。可以将这些想法结合起来,以避免需要显式的虚拟值

另一种选择是在
计算中生成valueOf abstract,避免对虚拟实例的依赖,将负担转移到计算实例创建上:

Calculation<MyInteger> calc = new Calculation<MyInteger>(
    new MyInteger(1), new MyInteger(2)) {
      public MyInteger valueOf(int i) {
        return new MyInteger(i);
      }
    });

Operations result = calc.sumPlusValue3();
Calculation calc=新计算(
新的MyInteger(1),新的MyInteger(2)){
公共My整数值(整数i){
返回新的MyInteger(i);
}
});
操作结果=计算sumPlusValue3();
总的来说,这似乎是“纯度”和“额外层次/复杂性”之间的正确平衡。我倾向于更加务实,在这里避免开销——以牺牲纯度为代价

另外,另一种选择可能是有一个显式的工厂接口,但将其存储为操作类的一个字段作为约定:

public final class MyInteger implements Operations{
  private final int delegate;

  public static final OperationsFactory<MyInteger> FACTORY = 
    new OperationsFactory<>() {
      @Override
      MyInteger valueOf(int i) {
        return new MyInteger(i);
      }
    };

  public MyInteger(int i){
      delegate = i;
  }

  @Override
  Operations add(Operations other){
      return new MyInteger(delegate + ((MyInteger) other).delegate);
  }
  @Override
  Operations subtract(Operations other){
    return new MyInteger(delegate - ((MyInteger) other).delegate);
  }
  (...)
}
public final类MyInteger实现操作{
私人代表;
公共静态最终操作工厂=
新操作工厂(){
@凌驾
我的整数值(int i){
返回新的MyInteger(i);
}
};
公共MyInteger(整数i){
代表=i;
}
@凌驾
操作添加(操作其他){
返回新的MyInteger(delegate+((MyInteger)other.delegate);
}
@凌驾
减法运算(其他运算){
返回新的MyInteger(委托-((MyInteger)other.delegate);
}
(...)
}
这至少可以将所有内容的实现端保存在一个文件中…

1)初始问题:工厂调用

在这里:

private final D value3 = D.valueOf(4);  // cannot implement this in interface 
您希望value
value3
带有非出厂的通用代码。
在接口中定义
valueOf()
(作为实例方法)也不是解决方案。

作为替代方案,您可以在
计算
构造函数中引入工厂参数,以便有一种方法来计算
值3

因此,请替换:

private final D value3 = D.valueOf(4);

public Calculation(D value1, D value2){
    this.value1 =value1;
    this.value2 = value2;
}
作者:

或者最好使用工厂的
功能
功能界面:

private final D value3; 

public Calculation(D value1, D value2, IntFunction<D> factoryD){
    this.value1 =value1;
    this.value2 = value2;
    this.value3 = factoryD.apply(4);
}
您应该使用一种方法来定义,以获取值,并使接口通用以处理任何类型的值:

public interface Operations<T> {

    Operations<T> add(Operations<T> op);

    Operations<T> subtract(Operations<T> op);

    T getValue();

}
计算
可以用两个泛型来定义:一个用于
操作
,另一个用于
操作
返回类型:

public class Calculation<C, D extends Operations<C>> {

    private final D value1, value2;
    private final D value3; 

    public Calculation(D value1, D value2, IntFunction<D> factoryD){
        this.value1 =value1;
        this.value2 = value2;
        this.value3 = factoryD.apply(4);
    }

    public Operations<C> sumPlusValue3(){
        return value1.add(value2).add(value3);
    }        
}
公共类计算{
私人最终估价1、估价2;
私人最终估价3;
公共计算(D值1、D值2、IntFunction factoryD){
此值为1.value1=value1;
此参数为0.value2=value2;
this.value3=工厂d.apply(4);
}
公共运营SumplusValue 3(){
返回值1.添加(值2).添加(值3);
}        
}
因此,您可以通过以下方式使用此代码:

Calculation<Integer, MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations<Integer> result = calc.sumPlusValue3();
System.out.println(result.getValue());
Calculation calc=new计算(new MyInteger(1)、new MyInteger(2)、MyInteger::new);
操作结果=计算sumPlusValue3();
System.out.println(result.getValue());
输出:

七,


我想将
int
添加到
double
,可以吗?考虑<代码>操作<代码>否,这不可能。这意味着必须验证所有操作实现是否属于同一实例。在Calculations类中,这是由于泛型参数而满足的,或者感谢返回类型提示。我还喜欢使用泛型函数/IntFunction的方法。对我来说,缺点是我有一个额外的参数,并且我可能需要一些其他的转换,例如D valueOf(String val),D valueOf(Int val)。。。您认为实例函数更适合这种情况吗?不客气。当您在
Calculation
中硬编码数值时,我建议创建一个D实例:
this.value3=factoryD.apply(4)
如果希望能够传递任何类型来构建D实例,可以指定
函数
函数。当然,在
Calculation
类中,您应该参考
C
类型,而不是数字或
String
值,因为
函数中的
C
类型是泛型而不是特定类型。如果必须使用sev
Calculation<MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations result = calc.sumPlusValue3();
public interface Operations{

    Operations add(Operations op);

    Operations subtract(Operations op);
}
public interface Operations<T> {

    Operations<T> add(Operations<T> op);

    Operations<T> subtract(Operations<T> op);

    T getValue();

}
public final class MyInteger implements Operations<Integer> {

    private final int delegate;

    public MyInteger(int i) {
      delegate = i;
    }

    @Override
    public Operations<Integer> add(Operations<Integer> other) {
      return new MyInteger(delegate + other.getValue());
    }

    @Override
    public Operations<Integer> subtract(Operations<Integer> other) {
      return new MyInteger(delegate - other.getValue());
    }

    @Override
    public Integer getValue() {
      return delegate;
    }
}
public class Calculation<C, D extends Operations<C>> {

    private final D value1, value2;
    private final D value3; 

    public Calculation(D value1, D value2, IntFunction<D> factoryD){
        this.value1 =value1;
        this.value2 = value2;
        this.value3 = factoryD.apply(4);
    }

    public Operations<C> sumPlusValue3(){
        return value1.add(value2).add(value3);
    }        
}
Calculation<Integer, MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations<Integer> result = calc.sumPlusValue3();
System.out.println(result.getValue());