2013-06-12 12 views
8

Come si scrive un costruttore di copie per una classe con variabili membro dell'interfaccia?È possibile scrivere i costruttori di copia per le classi con variabili membro di interfaccia in Java?

Per esempio:

public class House{ 

    // IAnimal is an interface 
    IAnimal pet; 

    public House(IAnimal pet){ 
     this.pet = pet; 
    } 

    // my (non-working) attempt at a copy constructor 
    public House(House houseIn){ 
     // The following line doesn't work because IAnimal (an interface) doesn't 
     // have a copy constructor 
     this.pet = new IAnimal(houseIn.pet); 
    } 
} 

Am I costretto ad avere una concreta Animal? Se è così, sembra riutilizzare la classe per le case con i cani contro le case con i gatti diventa contorta!

+1

Se si desidera una copia profonda, è necessario implementare anche un costruttore di copia in Animal. – alfasin

+1

Non è possibile semplicemente implementare un costruttore di copia in Animal. In questo caso hai IAnimal, un'interfaccia. Quindi dovresti sapere quale classe concreta hai bisogno di istanziare. – Mene

risposta

6

Hai una delle tre scelte:

  1. avere un metodo su IAnimal per clonare profondamente l'oggetto (usato da librerie come le interfacce DOM come Node.cloneNode(boolean))
  2. Creare un costruttore di copie in tutte le implementazioni di IAnimal che prende il tipo concreto e ne fa un requireme nt nel contratto di interfaccia, quindi utilizzare la reflection per accedervi
  3. Creare una copia factory che copierà ogni implementazione manualmente
  4. Utilizzare una libreria di terze parti che implementa la clonazione profonda per i propri contratti, ad esempio no-args costruttori, campi non finali, classi Serializable, ecc., Come quelli elencati here

Metodo Copy

Per # 1, fare qualcosa di simile:

public interface IAnimal { 
    IAnimal cloneDeep(); 
} 

Implementare che nelle vostre tipi concreti, quindi richiamare tale metodo per copiare:

this.pet = pet.cloneDeep(); 

Quindi documentare il requisito nell'interfaccia, ad esempio s omething lungo le linee di:

Implementazioni di questa interfaccia deve restituire un oggetto che non == è a questa istanza, e deve essere profondamente clonato in modo che la manipolazione di questo oggetto non comporti la manipolazione di quello restituito e viceversa.

Le implementazioni dovranno seguire questo contratto per essere conformi all'interfaccia, ma questo non verrà applicato in fase di compilazione.

Copia Constructor

tenta di accedere a un costruttore di copia riflessivo, quindi affermare che un costruttore di copia è richiesto in tutte le implementazioni concrete nel interfaccia, che diventa parte integrante del contratto di interfaccia. Ogni implementazione sarebbe quindi simile a questa:

public class Dog implements IAnimal { 

    private String name; 

    public Dog(Dog dog) { 
     this.name = dog.name; 
    } 
} 

E poi tutto ciò che serve è un unico metodo per copiare ogni implementazione:

public static <A extends IAnimal> A copy(A animal) { 
    Class<?> animalType = animal.getClass(); 
    // This next line throws a number of checked exceptions you need to catch 
    return (A) animalType.getConstructor(animalType).newInstance(animal); 
} 

Uno si dispone di questo, aggiungere una dichiarazione in tal senso nella vostra interfaccia di documentazione:

le implementazioni di questa interfaccia deve definire un costruttore di copia che prende un argomento dello stesso tipo o supertipo della loro classe. Questo costruttore deve fare una copia profonda dell'argomento in modo tale che la manipolazione di questo oggetto non porti alla manipolazione di quella restituita e viceversa.

Ancora, questo è il runtime applicato. Il metodo copy in alto genera errori NoSuchMethodException quando il costruttore non esiste.

copia di fabbrica

Questa prende il IAnimal e utilizza instanceof decidere quale metodo per passare a, come:

public static IAnimal copyAnimal(IAnimal animal) { 
    if (animal instanceof Dog) 
     return copyDog((Dog) animal); 
    if (animal instanceof Cat) 
     return copyCat((Cat) animal); 
    //... 
    else 
     throw new IllegalArgumentException("Could not copy animal of type: " 
       + animal.getClass().getName()); 
} 

Quindi eseguire la copia in profondità nelle copy metodi per ogni tipo manuale .

0

A mia conoscenza non esiste un equivalente diretto in Java.

Il modo "corretto" è quello di rendere l'interfaccia auto-implementata Cloanable.

E il modo più semplice potrebbe essere utilizzare la riflessione. So che esiste una biblioteca che gestisce copie profonde di oggetti arbitrari, ma al momento non riesco a ricordare il nome.

correlati: Java: recommended solution for deep cloning/copying an instance

+2

'Cloneable' è rotto in un sacco di modi, e in' Effective Java' Josh Bloch consiglia di non usarlo. Se non hai quel libro, dovresti. Vedi: http://www.artima.com/intv/bloch13.html –

2

Se ho ben capito il problema, dato che non è possibile specificare i costruttori in un'interfaccia si avrebbe bisogno di dichiarare un metodo profondo copia nella vostra interfaccia e attuarlo nelle classi. Non è possibile creare un'istanza di un'interfaccia. Potresti anche voler copiare a fondo qualcosa nel House, a seconda delle tue esigenze.

public interface IAnimal { 
    ... 
    IAnimal deepCopy(); 
} 


public House(House houseIn){ 
    this.pet = houseIn.pet.deepCopy(); 
} 

Il problema, naturalmente, è che sta a voi di fare che non fare qualcosa di sbagliato. Sembra che tu non voglia davvero un'interfaccia qui, ma piuttosto una classe astratta.

1

ok, lasciami spiegare un problema in questo codice. nota che quando hai un'interfaccia stai definendo un comportamento non un'astrazione o identità di un oggetto (o creatura) come un animale. in questo caso hai bisogno di una classe astratta invece di un'interfaccia. che inizia detto. non è possibile avere un costruttore su un'interfaccia (vedere Why are we not allowed to specify a constructor in an interface?), pertanto l'utilizzo di un'interfaccia in questo modo fallirà.

così via questo caso Io suggerirei di usare una classe astratta invece:

public class House { 

AbstractAnimal pet; 

public House(AbstractAnimal pet) { 
    this.pet = pet; 
} 

public House(House houseIn) { 
    this.pet = new AbstractAnimal(houseIn.pet) { 
     //implement the abstract methods that are required for anonymous class 
    }; 
} 

private abstract class AbstractAnimal { 
    //Abstract class attributes 

    public AbstractAnimal(AbstractAnimal Parent) { 
     //Constructor code, can also call abstract methods if required 
    } 
    //declare Abstract methods if required. 
} 
Problemi correlati