OOP concept: è possibile aggiornare la classe di un oggetto istanziato?

2

Sto provando a scrivere un semplice programma che dovrebbe consentire a un utente di salvare e visualizzare insiemi di dati eterogenei, ma in qualche modo correlati. Per chiarezza, userò un esempio rappresentativo di veicoli. Il flusso del programma è come questo:

  1. Il programma crea un oggetto Garage , che in pratica è una classe che può contenere un elenco di oggetti veicoli
  2. Quindi gli utenti creano oggetti Veicoli , questi veicoli hanno ciascuno una proprietà, diciamo Numero di targa . Una volta creato, l'oggetto Veicolo viene aggiunto a un elenco all'interno dell'oggetto Garage
  3. - Successivamente - l'utente può specificare che un determinato oggetto veicolo è in effetti un auto oggetto o oggetto Camion (dando così accesso ad alcuni attributi specifici come Numero di posti per la macchina, o Peso del carico per il camion)

A prima vista, questa potrebbe sembrare una domanda di un libro di testo OOP che coinvolge una classe base e un'eredità, ma il problema è più sottile perché al momento della creazione dell'oggetto (e fino a quando l'utente decide di fornire maggiori informazioni), il computer non lo fa so il tipo di veicolo esatto.

Di qui la mia domanda: come procederesti a implementare questo flusso di programma? OOP è la strada da percorrere?

Solo per dare una risposta iniziale, ecco cosa ho scoperto fino ad ora. Esiste solo una classe Vehicle e le varie proprietà / valori sono gestiti dal programma principale (non dalla classe) attraverso un dizionario. Tuttavia, sono abbastanza sicuro che ci deve essere una soluzione più elegante (sto sviluppando usando VB.net):

Public Class Garage
    Public GarageAdress As String
    Private _ListGarageVehicles As New List(Of Vehicles)

    Public Sub AddVehicle(Vehicle As Vehicles)
        _ListGarageVehicles.Add(Vehicle)
    End Sub
End Class

Public Class Vehicles
    Public LicensePlateNumber As String
    Public Enum VehicleTypes
        Generic = 0
        Car = 1
        Truck = 2
    End Enum
    Public VehicleType As VehicleTypes
    Public DictVehicleProperties As New Dictionary(Of String, String)
End Class

NOTA che nell'esempio sopra i modificatori pubblici / privati non riflettono necessariamente il codice originale

    
posta Federico 11.06.2013 - 00:46
fonte

4 risposte

6

No, non c'è modo di cambiare il tipo di un oggetto istanziato. Un Vehicle è un Vehicle , e rimarrà tale finché non esce dall'ambito.

Le tue scelte qui sono tre:

  1. Rendi il tipo di Vehicle semplicemente una proprietà sull'oggetto Vehicle e imposta l'impostazione predefinita su Unknown .
    • Funziona meglio quando c'è poca differenza funzionale tra Car e Truck .
    • Le funzioni possono restituire risultati diversi a seconda del VehicleType , e dovrai gestire il caso Unknown , ma è banale riassegnare.
  2. Sostituisci Vehicle con un nuovo oggetto di Car o Truck
    • Ciò richiederebbe un metodo IsActuallyACar() sul Vehicle che restituisce un Car , o un costruttore Car che prende un Vehicle come argomento (che è la scelta migliore) .
    • L'utilizzo di questo metodo richiede la rimozione manuale di Vehicle da qualsiasi posizione in cui è memorizzato e la sostituisce con l'oggetto appena creato.
  3. Ripensa il tuo disegno in modo che Vehicle sia astratto e non crei l'oggetto finché non sai di che tipo si tratta.
    • Questa è probabilmente l'opzione migliore da una prospettiva OO.
    • Potrebbe essere necessario memorizzare temporaneamente i dati in una struttura non Vehicle mentre li raccogli, ma non devi preoccuparti di cambiare il tipo in seguito.

Nel tuo scenario descritto, sospetto che il # 1 sia la scelta migliore. Basta avere la logica che dice "Se l'oggetto ha il suo tipo impostato su Car , quindi mostra questo, se è impostato su Truck mostra questo." Non è un ottimo design OOP, ma gestisce il "Veicolo di tipo sconosciuto" il migliore.

    
risposta data 11.06.2013 - 01:18
fonte
1

No, non è possibile modificare la classe di un oggetto una volta istanziato, almeno non in alcun linguaggio di programmazione che conosca. La ragione è che questo potrebbe far saltare in aria ogni tipo di garanzia che una gerarchia di classe ti darebbe altrimenti; per non parlare del fatto che "cambiare la classe di un oggetto" è un requisito altamente indefinito - come si fa a migrare lo stato dell'oggetto? Come si mappano i campi da una classe all'altra?

Considerando il tuo problema a portata di mano; sei caduto vittima della seduzione del polimorfismo ingenuo e del riutilizzo per eredità. Mentre sia un Car che un Truck sono veicoli, non è molto saggio averli ereditati da Vehicle direttamente e codificare tutto il comportamento in queste tre classi. In altre notizie, il libro di testo è sbagliato.

Invece, suddividere la funzionalità in componenti. Un Vehicle ha una targa e un tipo. Il tipo determina se si tratta di un'automobile o di un camion. È quindi possibile scambiare il tipo di veicolo senza cambiarne le proprietà di base.

Inoltre, tieni presente che probabilmente stai mentendo sui tuoi dati. Crei un oggetto Vehicle senza avere effettivamente un veicolo a portata di mano; tutto quello che vuoi è memorizzare il numero di targa. Quindi, magari inserire la targa nella propria classe e collegarla successivamente a un veicolo reale potrebbe essere una scelta di design migliore.

    
risposta data 11.06.2013 - 10:41
fonte
0

Userei un design diverso in cui garage contiene un elenco di oggetti parkingspace. L'oggetto parkingspace implementerebbe l'interfaccia Licensplate.

Ora vorrei che l'oggetto veicolo implementasse anche l'interfaccia per le licenze.

In questo modo puoi istanziare la tua lista di spazi di parcheggio, con numeri di targa di licenza corrisposti e istanziare le tue auto e camion in seguito con le targhe di licenza.

    
risposta data 11.06.2013 - 12:37
fonte
0

probabilmente stai cercando questo modello

devi modificare questo codice in base alle tue esigenze.

public interface IVehicle
{  
    string VehicleType{get;}
    int NumberOfSeets{set;get;}
    int Corgosize{set;get;}
}

public class Car:IVehicle
{
    private int _numseets;
    private int _corgo;
    public string VehicleType{
        get{return "CAR";}
    }

    public int NumberOfSeets
    { 
       get{return _numseets;}
       set{_numseets = value;}
    }

    public int Corgosize
    {
        get { return _corgo; }
        set { _corgo = value; }
    }
}

public class Truck : IVehicle
{
    private int _numseets;
    private int _corgo;
    public string VehicleType
    {
        get { return "Truck"; }
    }

    public int NumberOfSeets
    {
        get { return _numseets; }
        set { _numseets = value; }
    }

    public int Corgosize
    {
        get { return _corgo; }
        set { _corgo = value; }
    }
}

public class Vehicle : IVehicle
{
    private IVehicle _vehicle;
    public Vehicle(IVehicle refVehicle)
    {
        _vehicle = refVehicle;
    }
    public string VehicleType
    {
        get { return _vehicle.VehicleType; }
    }

    public int NumberOfSeets
    {
        get { return _vehicle.NumberOfSeets; }
        set {  }
    }

    public int Corgosize
    {
        get { return _vehicle.Corgosize; }
        set {  }
    }

}

public class MainClass
{
    public static void Main()
    {
        Vehicle car, truck;
        car = new Vehicle(new Car());
        truck = new Vehicle(new Truck());
        Console.WriteLine("Car type ->{0}",car.VehicleType);
        Console.WriteLine("truck type ->{0}", truck.VehicleType);
        Console.ReadKey();

    }

}
    
risposta data 25.06.2013 - 00:53
fonte

Leggi altre domande sui tag