2009-04-23 21 views
6

Questa può essere una domanda per principianti ma esiste un metodo standard per rifattorizzare la duplicazione della proprietà Wheel nella classe astratta, mantenendo tuttavia il cast esplicito per il tipo di Parte. Supponiamo di dover impedire a FastCarWheel di essere inserito in uno SlowCar e che ci siano molte proprietà come questa.Domanda di base sul refactoring in una classe astratta

abstract class Car {} 

class FastCar : Car 
{ 
    public FastCarWheel Wheel { get; set; } 
} 

class SlowCar : Car 
{ 
    public SlowCarWheel Wheel { get; set; } 
} 

abstract class WheelPart {} 

class FastCarWheel: WheelPart {} 

class SlowCarWheel: WheelPart {} 

In questo tipo di scenario è comune consentire solo questo tipo di duplicazione? Stavo pensando di fare uso di Generics ma sembra che sto spostando il problema, e peggiora per ogni proprietà aggiuntiva che si comporta in questo modo.

abstract class Car <P> 
    where P : Part 
{ 
    protected abstract P Wheel { get; set; } 
} 

Grazie

risposta

0

definire un'interfaccia ruota (IWheel):

public interface IWheel 
{ 
} 

implementare l'interfaccia per FastCarWheel e SlowCarWheel esempio

public class FastCarWheel : IWheel 
{ 
} 

Ora la vostra classe astratta diventa:

abstract class Car 
{ 
public IWheel Wheel { get; set; } 
} 

sottoclassi di auto sono quindi liberi di utilizzare qualsiasi applicazione della rotella scelgono:

FastCar fastCar = new FastCar(); 
fastCar.Wheel = new FastCarWheel(); 
+0

Questo è il problema, però. NON vuole che nessuna macchina abbia alcun tipo di ruota. Vuole che FastCars abbia solo FastWheels e SlowCars abbia solo SlowWheels. Un'interfaccia non lo farebbe. – Joseph

+0

Se una FastCar non può avere una SlowCarWheel, quella logica appartiene a FastCar e non nella classe base. –

+0

Sono d'accordo, ma il problema è che il tuo codice promuoverà l'uso di questo (fastCar.Wheel = new SlowCarWheel();) che ha esplicitamente detto che non voleva consentire. Sono d'accordo, tuttavia, che questa logica non appartiene alla classe base. – Joseph

1

Credo che utilizzando un Fast o Slowpolicy può aiutare a mettere la ruota corretto per un determinato tipo di autovettura (dove entrambi Car e Wheel dipendono dalla politica e un oggetto Car ha, ad esempio, un aggregration privato di ruote).

1

Questa soluzione non è polimorfica, ma potrebbe essere l'unica opzione se hai bisogno di una visibilità a livello di classe di base:

abstract class Car 
{ 
    private CarWheel wheel; 
    public CarWheel Wheel 
    { 
     get { return wheel; } 
     protected set { wheel = value; } 
    } 
} 

class FastCar : Car 
{ 
    public new FastCarWheel Wheel 
    { 
     get { return base.Wheel as FastCarWheel; } 
     set { base.Wheel = value; } 
    } 
} 

class SlowCar : Car 
{ 
    public new SlowCarWheel Wheel 
    { 
     get { return base.Wheel as SlowCarWheel ; } 
     set { base.Wheel = value; } 
    } 
} 

Si potrebbe desiderare di valutare se la classe base sta facendo troppo. Potrebbe essere possibile risolvere il problema suddividendo le classi in molte classi più piccole. D'altra parte, a volte è inevitabile.

1

vorrei creare un ICAR e quindi definire le vostre auto in questo modo, invece di una classe astratta

interface ICar 
{ 
    IWheel Wheel {get; set;} 
} 

class FastCar: ICar 
{ 
    FastWheel fastWheel; 
    IWheel Wheel 
    { 
     get { return fastWheel; } 
     set 
     { 
      if (value is FastWheel) fastWheel = (FastWheel)value; 
     }  
    }   
} 

class SlowCar: ICar 
{ 
    SlowWheel slowWheel; 
    IWheel Wheel 
    { 
     get { return slowWheel; } 
     set 
     { 
      if (value is SlowWheel) slowWheel = (SlowWheel)value; 
     }  
    } 
} 

class FastWheel: IWheel {} 
class SlowWheel: IWheel {} 
1

Dal momento che il vostro obiettivo sembra essere consentendo il codice del client per ottenere la proprietà indietro come un WheelPart, ma solo impostalo come una sottoclasse specifica hai un paio di opzioni. Anche se ho paura che nessuno dei due sia molto pulito.

In primo luogo si potrebbe lanciare un errore di runtime se il tipo sbagliato è impostato:

public abstract class Car 
    { 
     public abstract WheelPart Wheel { get; set; } 
    } 

    public class FastCar : Car 
    { 
     private FastWheel _wheel; 
     public override WheelPart Wheel 
     { 
      get { return _wheel; } 
      set 
      { 
       if (!(value is FastWheel)) 
       { 
        throw new ArgumentException("Supplied wheel must be Fast"); 
       } 
       _wheel = (FastWheel)value; 
      } 
     } 
    } 

ma non vorrei fare questo in quanto è molto chiaro per il codice client che qualsiasi altro tipo di ruota genera un eccezione, e non riceveranno feedback del compilatore.

In caso contrario si potrebbe separare i getter e setter per la proprietà in modo che il tipo di richiesta è molto chiara:

public abstract class Car 
    { 
     public abstract WheelPart Wheel { get; } 
    } 

    public class FastCar : Car 
    { 
     private FastWheel _wheel; 
     public override WheelPart Wheel 
     { 
      get { return _wheel; } 
     } 

     public void SetWheel(FastWheel wheel) 
     { 
      _wheel = wheel; 
     } 
    } 

Questo è molto più chiaro per il cliente e secondo me una soluzione più bello se si deve assolutamente esporre il getter come base della classe WheelPart.

+0

La seconda soluzione sembra carina. – Greg

Problemi correlati