我有一个界面Operations
:
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);
}
(...)
}
在其他类中,将根据接口Operations
的功能进行计算。但有时我需要一个静态上下文,如valueOf(val)
函数,它返回给定String,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<MyInteger> calc = new Calculation<MyInteger>(new MyInteger(1), new MyInteger(2));
Operations result = calc.sumPlusValue3();
一般来说,我认为我必须使用Builder或Factory之类的设计模式来允许用户指定他想要的实现,例如
Operations integerImpl = OperationsBuilder.create("Integer");
但是在研究了这些模式之后,我找不到一种干净的方法来在D
类中为value3
获得泛型类Calculation
的实现。
编辑1 :
我编辑了这个问题并标记了来自@Stefan Haustein的答案,因为它是我问题的最佳解决方案。
但是@davidxxx的答案对于我的初始问题也是一个很好的答案 - 如何表示仅 valueOf(int val)
函数。
答案 0 :(得分:2)
1)初始问题:工厂调用
这里:
private final D value3 = D.valueOf(4); // cannot implement this in interface
您希望值value3
具有非工厂的通用。
在接口中定义valueOf()
(以及实例方法)不是解决方案。
作为替代方案,您可以在Calculation
构造函数中引入工厂参数,以便有机会估算value3
。
所以替换:
private final D value3 = D.valueOf(4);
public Calculation(D value1, D value2){
this.value1 =value1;
this.value2 = value2;
}
by:
private final D value3;
public Calculation(D value1, D value2, FactoryD factoryD){
this.value1 =value1;
this.value2 = value2;
this.value3 = factoryD.create(4);
}
或更好地使用工厂的Function
功能界面:
private final D value3;
public Calculation(D value1, D value2, IntFunction<D> factoryD){
this.value1 =value1;
this.value2 = value2;
this.value3 = factoryD.apply(4);
}
你可以这样使用它:
Calculation<MyInteger> calc = new Calculation<>(new MyInteger(1), new MyInteger(2), MyInteger::new );
Operations result = calc.sumPlusValue3();
但是Operations
错过了一些东西。
2)无法表示Operations
值。
实际上,Operations
定义了操作方法,但无法显示对象值:
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();
}
MyInteger
可以定义为:
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;
}
}
Calculation
可以使用两个泛型来定义:一个用于Operations
,另一个用于Operations
返回类型:
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());
输出:
7
答案 1 :(得分:1)
如果在Calculation
中你总是有一个D
附近的实例,你可以让valueOf
成为Operations
的非静态成员,尽管从技术上来说你不会&#39} ; t需要相应的值。
如果使用&#34;虚拟&#34; valueOf
的实例不是一个选项,您可能需要Class<D>
作为Calculations
的构造函数参数。这将允许您调用newInstance()
,也许提供一个中性元素 - 但您仍然需要addInt
之类的操作才能获得具体值。可以将这些想法结合起来,以避免需要明确的虚拟值。
另一种选择是在Calculation
中使valueOf为abstract,避免对虚拟实例的依赖,将负担转移到Calculation实例创建:
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();
一般来说,这似乎是关于&#34;纯度&#34;之间的正确平衡。和&#34;额外的层/复杂性&#34;。我倾向于更加务实,避免在这里花费 - 以牺牲纯度为代价。
P.S。另一种选择可能是拥有一个显式的工厂接口,但可以将其作为约定存储为Operations类的字段:
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);
}
(...)
}
这至少可以将所有内容的实现方保存在一个文件中......