¿La clonación de proporcionar una mejora del rendimiento a través de constructores/métodos de fábrica?

StackOverflow https://stackoverflow.com/questions/663079

Pregunta

Estoy a mantener una mayor Java base de código (jvm 1.4) que parece usar la clonación como una alternativa a la creación de instancias de objeto, supongo que como una optimización del rendimiento.He aquí un ejemplo inventado:

public class Foo {
  private SomeObject obj; // SomeObject implements Cloneable
  public Foo() {
    obj = new SomeObject();
    obj.setField1("abc"); // these fields will have the same value every time
    obj.setField2("def");
  }
  public void doStuff() {
    SomeObject newObj = obj.clone(); // clone it instead of using a factory method
    // do stuff with newObj
  }
}

Las habituales advertencias sobre la optimización no obstante, fue este hecho se recomienda una expresión idiomática en algún momento?

¿Fue útil?

Solución

Una de las razones para invocar clone() en lugar de la copia constructor o un método de fábrica es que ninguna de las otras opciones que pueden estar disponibles.

La aplicación de clone() para realizar una profunda objeto de copia (copia profunda es más implicados) es trivial en comparación con la implementación de un constructor de copia o un método de fábrica para realizar la misma operación.Para implementar clone(), una clase, simplemente, de aplicar la Cloneable la interfaz y el método de reemplazo de clone() con uno que invoca super.clone() que por lo general llama Object.clone(). Object.clone() copias de todas las propiedades del objeto original en la propiedad correspondiente de los duplicados, por lo tanto la creación de una copia superficial.

A pesar de la implementación de clone() es sencillo, es fácil olvidar a implementar Cloneable.En consecuencia, un riesgo potencial de uso de clone() para duplicar un objeto es que si la clase de ese objeto no descuidar a implementar Cloneable y clone() invoca Object.clone() ya sea directa o indirectamente, lanzará CloneNotSupportedException.

Ver este ejemplo de código y una anterior discusión en el un mal diseño de la Cloneable la interfaz.

Otros consejos

Presumiblemente querían una copia. Quizás quieran pasarlo a otra función, y no pueden estar seguros de que esa función no lo cambiará. Es una forma de asegurarse de que el método doStuff () sea constante con respecto al estado del objeto Foo al que se llama.

Un problema importante con los constructores de copia es que el tipo de objeto debe conocerse en tiempo de compilación. Si una clase heredable admite un constructor de copia, y al constructor se le pasa un objeto de clase derivada, el constructor producirá un objeto de clase base cuyas propiedades de clase base generalmente coinciden con las del objeto pasado, pero el nuevo objeto ganó ' No admite las características que estaban presentes en el objeto pasado que no estaban presentes en la clase base.

Es posible resolver este problema de alguna manera haciendo un constructor de copia & "; protegido &"; y teniendo un método de copia de fábrica reemplazable en cada clase derivada que llama al propio constructor de copia de esa clase, que a su vez llama al constructor de copia de su clase base. Sin embargo, cada clase derivada necesitará un constructor de copia y una anulación del método de copia, independientemente de si agrega o no nuevos campos. Si la clase de caso usa & Quot; clone & Quot ;, este código adicional puede eliminarse.

Puede ser una optimización del rendimiento, dependiendo de cuánto trabajo se haga en los constructores.

Es más probable que se use porque la semántica es diferente. La clonación proporciona una forma de implementar & Quot; semántica prototipo & Quot; (como en javascript, self, etc.) en un lenguaje que normalmente no suele ser así.

Si el constructor SomeObject hace un trabajo costoso, como tomar algo de una base de datos o analizar algo, o leer algo de un archivo, entonces el clon tendría sentido para evitar hacer el trabajo.

Si el constructor no hace nada, entonces realmente no hay necesidad de usar clon.

Editar: código agregado para mostrar que el clon no tiene que hacer el mismo trabajo que el constructor:

class Main
    implements Cloneable
{
    private final double pi;

    public Main()
    {
        System.out.println("in Main");
        // compute pi to 1,000,000,000 decimal palaces
        pi = 3.14f;
    }

    public Object clone()
    {
        try
        {
            return (super.clone());
        }
        catch(final CloneNotSupportedException ex)
        {
            throw new Error(); // would not throw this in real code
        }
    }


    public String toString()
    {
        return (Double.toString(pi));
    }

    public static void main(String[] args)
    {
        final Main a;
        final Main b;

        a = new Main();
        b = (Main)a.clone();

        System.out.println("a = " + a);
        System.out.println("b = " + b);
    }
}

El constructor principal se llama una vez, la computación pi se realiza una vez.

Licenciado bajo: CC-BY-SA con atribución
No afiliado a StackOverflow
scroll top