Java - 当你拥有的所有对象都是引用类型时,实例化它

时间:2009-11-06 18:33:43

标签: java interface copy types

我快速查看了“相关问题”,但我找不到与我所问的内容直接相关的问题。即使有一个,我仍然感谢你对最佳方法的看法。

首先是一些背景 我正在扩展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)没有意义。我想我可以在我的界面上添加克隆方法而不是复制构造函数,但正如我之前所说,我很感激你对此事的看法。

提前致谢,
约恩

7 个答案:

答案 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()并执行深度克隆(如果相关)(原则上只有实现类知道这一点)。

采用反射性可能会影响性能并使扩展设计更复杂(太?)复杂。这里的另一个选择是提供一个抽象类,它具有复制构造函数而不是接口,但是有明显的限制,可能是一个显示停止。