Continuiamo con lo smell: Indecent Exposure
 

Problema:
Il client istanzia 
direttamente un oggetto che risiede in una libreria.
 
Motivazione:
Durante la realizzazione di una libreria, si potrebbe cadere nella tentazione di creare delle classi che istanziano oggetti di cui il client necessita.
Un esempio di logica errata: 
 
 
Ciò significa dare al client la responsabilità di conoscere tutti gli oggetti presenti nella nostra libreria.
    
        
            |  class Program{
 static void Main(string[] args)
 {
 List<AttributeDescriptor> lstAttDesc = new List<AttributeDescriptor>();
 lstAttDesc.Add(new BooleanDescriptor("boolean"));
 lstAttDesc.Add(new DefaultDescriptor("primo", typeof(string), 10));
 lstAttDesc.Add(new ReferenceDescriptor("secondo", typeof(MiaClasse), sizeof(MiaClasse)));
 // ...
 }
 }
 
 public abstract class AttributeDescriptor
 {
 protected AttributeDescriptor()
 {
 // ...
 }
 }
 
 public class BooleanDescriptor : AttributeDescriptor
 {
 public BooleanDescriptor(string name)
 : base()
 {
 // ...
 }
 }
 
 public class DefaultDescriptor : AttributeDescriptor
 {
 public DefaultDescriptor(string name, Type t, long length)
 : base()
 {
 // ...
 }
 }
 
 public class ReferenceDescriptor : AttributeDescriptor
 {
 public ReferenceDescriptor(string name, Type t, long length)
 : base()
 {
 // ...
 }
 }
   | 
    
 
E ciò è un male == smells.
Soluzione:
Tenendo presente la regola: far lavorare il client tramite interfacce e non tramite oggetti.
Ne consegue che, quanto sopra, si potrebbe risolvere con un Factory pattern:
    
        
            |  class Program{
 static void Main(string[] args)
 {
 List<AttributeDescriptor> lstAttDesc = new List<AttributeDescriptor>();
 lstAttDesc.Add(AttributeDescriptor.CreateBoolean("boolean"));
 lstAttDesc.Add(AttributeDescriptor.CreateDefault("primo", 10));
 lstAttDesc.Add(AttributeDescriptor.CreateReference("secondo", typeof(MiaClasse), sizeof(MiaClasse)));
 // ...
 }
 }
 
 public abstract class AttributeDescriptor
 {
 protected AttributeDescriptor()
 {
 // ...
 }
 
 public static AttributeDescriptor CreateBoolean(string name)
 {
 return new BooleanDescriptor(name);
 }
 
 public static AttributeDescriptor CreateDefault(string name, long length)
 {
 return new DefaultDescriptor(name, typeof(string), length);
 }
 
 public static AttributeDescriptor CreateReference(string name, Type t, long length)
 {
 return new ReferenceDescriptor(name, t, length);
 }
 }
 
 public class BooleanDescriptor : AttributeDescriptor
 {
 public BooleanDescriptor(string name)
 {
 // ...
 }
 }
 
 public class DefaultDescriptor : AttributeDescriptor
 {
 public DefaultDescriptor(string name, Type t, long length)
 {
 // ...
 }
 }
 
 public class ReferenceDescriptor : AttributeDescriptor
 {
 public ReferenceDescriptor(string name, Type t, long length)
 {
 // ...
 }
 }
 | 
    
 
Questa è una possibile soluzione
Da notare che classi BooleanDescriptor, DefaultDescriptor e ReferenceDescriptor, dopo il Refactoring, il client non ha nessun bisogno di sapere come queste sono implementate e possono risiedere in qualsiasi dll, il client avrà solamente bisogno di referenziare la classe AttributeDescriptor
 
 
    
        
            | Benefici e non + Semplifica la creazione delle istanze degli oggetti.
 + Allegerisce la conoscenza da parte del client delle classi e della loro implementazione.
 + Mantiene viva la regola sull’utilizzo delle interfacce.
 - Bisogna creare un metodo Create per ogni oggetto.
 - Limita le customizzazioni da parte del client perchè può accedere solo all’interfaccia.
 | 
    
 
E non prendete come scusa: “il mio sistema ormai è troppo evoluto per poterne apportare queste migliorie. E’ troppo tardi.”
Se fosse realmente così non esisterebbe il Refactoring :)
Per questi post sto prendendo, molto, spunto da libro Refactoring To Patterns di Joshua Kerievsky.