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.