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
您希望valuevalue3
带有非出厂的通用代码。
在接口中定义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());