我快速查看了“相关问题”,但我找不到与我所问的内容直接相关的问题。即使有一个,我仍然感谢你对最佳方法的看法。
首先是一些背景 我正在扩展Java应用程序,我有以下接口和类:
public interface Mapper {
public void foo();
}
public class SomeGrammar implements Mapper {
public SomeGrammar() {}
public SomeGrammar(SomeGrammar toCopy) {
//Copy specific fields
}
public void foo() {}
}
我正在使用的应用程序只考虑了一种语法类型SomeGrammar
,因此SomeGrammar
类在整个应用程序中编织。
SomeGrammar
个对象:
SomeGrammar aGrammar = new SomeGrammar();
SomeGrammar newGrammar = new SomeGrammar(aGrammar);
我正在尝试实现新类型的语法。所以我打算将核心方法拉出来并实现Grammar
接口,甚至将这些方法合并到Mapper
接口中。所以所有语法类都会实现这个接口。
无论如何,我的问题是,更换上述行的最佳方法是什么,以便我可以概括当前正在被接口类型引用的任何语法对象的复制?
显然我不能
Grammar newGrammar = new Grammar(aGrammar);
因为Grammar
是接口的类型,new Grammar(aGrammar)
没有意义。我想我可以在我的界面上添加克隆方法而不是复制构造函数,但正如我之前所说,我很感激你对此事的看法。
提前致谢,
约恩
答案 0 :(得分:3)
如果我理解你的问题,我的解决方案将如下所示:
让我们说我们有3个具体的语法,我们希望创建,GrammarA,GrammarB和GrammarC。我们将定义每个类来实现语法接口。 GrammarInterface将具有您的foo()函数,并且还定义了doCopy()函数。然后,每个具体的语法类将负责实现foo()功能,并通过调用复制构造函数返回自己的副本。这是你在找什么?
interface IGrammar {
public void foo();
public Grammar doCopy();
}
class GrammarA implements IGrammar {
public Grammar doCopy(Grammar g) {
return new GrammarA(g);
}
}
答案 1 :(得分:1)
Object.clone()不好,请参阅Effective Java进行讨论。
标记接口不好(参见Externalizable,Serializable,...)有大量的库试图绕过这种无用的标记接口。
Cloneable<T>
可能是一种方法。
我建议Factory
:
Grammar someGrammar = Factory.newGrammar();
Grammar copyOf = Factory.copyGrammar(someGrammer);
原因是,如果它是Cloneable,Factory可以委托语法对象,但它也可以做其他事情,例如保留创建语法列表或返回适配器或返回缓存实例(一般来说,独立于实际的语法实现)。此外,实现类不需要在整个应用程序中直接使用。
答案 2 :(得分:0)
您可以添加clone()
作为界面的一部分,并让具体的类正确实现它。然后您的客户端代码将如下所示:
Grammar aGrammar = new SomeGrammar();
Grammar newGrammar = aGrammar.clone();
查看一些解释here。就个人而言,我建议您将copy()
方法作为Grammar
界面的一部分。这比重用clone()
恕我直言更好。
答案 3 :(得分:0)
我认为您想要的是Grammar
界面包含makeCopy
签名。
然后制作副本看起来像:
Grammar newGrammar = oldGrammar.makeCopy();
避免使用clone
方法,因为这种方式是疯狂的!
答案 4 :(得分:0)
您还可以使用反射来查找语法的类型,并使用匹配的构造函数创建此类型的新实例:
interface Interface {
}
class A implements Interface {
public A(Interface other) {
}
}
class B implements Interface {
public B(Interface other) {
}
}
public class Test {
public static Interface newWithExactType(Interface i) throws Exception {
Class<? extends Interface> c = i.getClass();
Constructor<? extends Interface> ctor = c.getConstructor(Interface.class);
return ctor.newInstance(i);
}
public static void main(String[] args) throws Exception {
Interface a = newWithExactType(new A(null));
Interface b = newWithExactType(new B(null));
System.out.println("Type of a: "+a.getClass().getSimpleName());
System.out.println("Type of b: "+b.getClass().getSimpleName());
}
}
答案 5 :(得分:0)
如果你真的需要能够在多个不同的实现之间进行复制,我建议采用以下方法:
public interface Mapper {
void Mapper();
void Mapper(Mapper copy);
Foo getFoo();
Bar getBar();
// getters for shared properties which can be copied between implementations
void doStuff();
}
public abstract AbstractBaseMapper implements Mapper {
protected Foo foo;
protected Bar bar;
public void Mapper() {}
public void Mapper(Mapper copy) {
foo = copy.getFoo();
bar = copy.getBar();
}
public Foo getFoo() { return foo; }
public Bar getBar() { return bar; }
}
public ConcreteMapper extends AbstractBaseMapper {
public void doStuff() {
}
}
public AnotherMapper extends AbstractBaseMapper {
public void doStuff() {
}
}
public YetAnotherMapper implements Mapper {
// NB: this one is a straight implementation of the Mapper interface, doesn't inherit from AbstractBaseMapper...
}
现在你可以做类似的事情:
Mapper m1 = new YetAnotherMapper();
Mapper m2 = new ConcreteMapper(m1);
Mapper m3 = new AnotherMapper(m2);
这种方法的缺点是你必须在基接口中定义所有可复制字段,以便始终保证它们的实现。另一种方法是使用Karl建议的反射。您还可以查看自动执行此类反射属性复制的Dozer。
答案 6 :(得分:-1)
IMO最好的选择就是拥有
public interface Mapper extends Cloneable {
public Object clone();
}
让该方法调用super.clone()
并执行深度克隆(如果相关)(原则上只有实现类知道这一点)。
采用反射性可能会影响性能并使扩展设计更复杂(太?)复杂。这里的另一个选择是提供一个抽象类,它具有复制构造函数而不是接口,但是有明显的限制,可能是一个显示停止。