Non specifichi la lingua che stai usando, ma suggerirei che un approccio sarebbe avere la classe base che dovrebbe avere un protected metodo cloneBase , e quindi per ogni classe che potrebbe supportare la clonazione avere un derivato concreto sigillato che implementa un'interfaccia di clonazione tipicamente tipicamente covariante, con se stesso come parametro di tipo generico. Può essere utile che questa interfaccia includa anche un metodo che le implementazioni useranno per restituire se stessi, digitato in base al parametro generico.
Se AnimalBase non avrebbe difficoltà a supportare la clonazione, ma alcune classi derivate potrebbero avere oggetti non clonabili, quindi Animal dovrebbe essere una classe sigillata che deriva da AnimalBase e implementa ICloneable<Animal> . Se BirdBase deriva da animale, Bird sarebbe un derivato di ciò che implementa ICloneable<Bird> . Se Phoenix deriva da Bird ma non supporta la clonazione, né esso né alcun derivato implementeranno alcuna interfaccia ICloneable .
Utilizzando questo approccio, il codice che ha bisogno di qualcosa che è clonabile e deriva da AnimalBase potrebbe accettare un parametro di tipo ICloneable<AnimalBase> ; un tipo di questo tipo potrebbe accettare Animal o Bird , anche se questi tipi non sono correlati. Il codice che deve utilizzare ICloneable<AnimalBase> come AnimalBase potrebbe utilizzare il suo membro Self .
In alternativa, si potrebbe implementare una proprietà% / metodo IsCloneable e quindi avere un metodo Clone che è garantito funzionare solo se IsCloneable restituisce true. Un simile approccio non fornirebbe un modo per indicare a un tipo di compilazione che aveva bisogno di qualcosa che può essere clonato, ma eviterebbe la necessità di tipi "foglia" extra sigillati. Anche se c'è un certo vantaggio che i metodi esprimano i loro requisiti attraverso i loro parametri, c'è anche il vantaggio di evitare la creazione di tipi altrimenti inutili.