Creazione di un'istanza di una classe complicata

2

Come posso creare istanze di classi che richiedono una grande quantità di componenti e attributi? Prendi ad esempio una macchina. Un'auto ha centinaia di sotto componenti ciascuno con le proprie proprietà specifiche. Ci sarebbero migliaia di parametri per passare o lavorare con. Alcuni componenti si ripetono anche all'interno dell'auto (ruote, porte, freni, molle, ecc.). Ho fatto due classi di auto dimostrative e ho inventato due modi per inizializzarle. Neanche io sono felice.

First Way : annida tutte le sottoclassi e inizializza l'auto con un'enorme affermazione. Non mi piace perché non posso creare prima i componenti secondari e costruire lentamente. Cosa succede se non so quanto saranno grandi le ruote, cosa faccio? Devo specificare i valori di default? Cosa succede se ho bisogno di più porte? Questo sarebbe utilizzabile se la classe avesse effettivamente bisogno di migliaia di argomenti come una vera macchina?

Class Car(Size, TireType, Displacement, Cylinders, ECU, Fuel Type, PowerLockButton, Gears, ShiftLeverLength, ClutchType, GearKnob, Computer, TorqueConverter, FluidType, Links, SpringRate, BushingMaterial, ShockType)
    Class Wheels(Size, TireType)
    Class Engine(Displacement, Cylinders, ECU, Fuel Type)
    Class Door(PowerLockButton)
    Class Transimission(Gears)
    Class ManaulTransmission Inherits From Transmission(ShiftLeverLength, ClutchType, GearKnob)
    Class AutomaticTransmission Inherits From Transimission(Computer, TorqueConverter, FluidType)
    Class Suspension(Links, SpringRate, BushingMaterial, ShockType)

FordMustang = Car(20", Michelin, 5.0L, 8Cylinders, Delphi, Gasoline, NoPowerLock, 6Gears, 3inches, SportClutch, MetalKnob, StiffLinks, 550lbRate, PolyUrethaneBushing, MagneticShocks)
BMW530i = Car(18", Continental, 3.0L, 6Cylinders, Bosch, Gasoline, YesPowerLock, 6Gears, BoschTransComputer, MediumTorqueConverter, ExpensiveFluid, ModerateLinks, 45lbRate, RubberBushing, SachsShocks)

Secondo passaggio: crea le classi di componenti Car e poi le aggregale tutte in una classe di auto. Non mi piace perché devo usare molte linee di codice per costruire l'auto e quel codice sembra orfano seduto allo scoperto. Inoltre, non utilizzerò mai nessuno di questi componenti (ruota, motore, trasmissione, ecc.) In qualcosa di diverso dall'interno di un'auto, quindi perché lasciarli al di fuori dell'ambito della classe dell'auto?

Class Wheels(Size, TireType)
Class Engine(Displacement, Cylinders, ECU, Fuel Type)
Class Door(PowerLockButton)
Class Transimission(Gears)
Class ManaulTransmission Inherits From Transmission(ShiftLeverLength, ClutchType, GearKnob)
Class AutomaticTransmission Inherits From Transimission(Computer, TorqueConverter, FluidType)
Class Suspension(Links, SpringRate, BushingMaterial, ShockType)

Class Car(Wheels, Engine, Door, Transimission, Suspension)

BMW530iWheels = Wheels(18', Continental)
BMW530iEngine = Engine(3.0L, 6Cylinders, Bosch, Gasoline)
BMW530iDoor = Door(YesPowerLock)
BMW530iTransmission =  AutomaticTransmission(6Gears, BoschTransComputer, MediumTorqueConverter, ExpensiveFluid)
BMW530iSuspension = Suspension(ModerateLinks, 45lbRate, RubberBushing, SachsShocks)

BMW530i = Car(BMW530iWheels, BMW530iEngine, BMW530iDoor, BMW530iTransmission, BMW530iSuspension)

Qualche idea su come questo può essere fatto in modo affidabile? La mia preoccupazione è che l'uno o l'altro modo che prendo diventerà travolgente da usare quando il numero di attributi è estremamente alto. Ciò che mai puoi contribuire sarà molto apprezzato.

    
posta supertommy 01.02.2017 - 01:37
fonte

2 risposte

4

Usa lo schema Builder

Il Builder Pattern è inteso esattamente per questo scenario.

Parametri nominati

In questo esempio combino il modello di builder con parametri con nome per rendere più chiaro ciò che viene costruito:

var builder = new CarBuilder();
builder.WithWheels(17, WheelType.Aluminum);
builder.WithEngine(displacement: 2.1F, 
                   cylinders:    4, 
                   ecu:          EcuType.Programmable, 
                   fuel:         FuelType.Unleaded);
builder.WithDoors(powerlock: true);
var car = builder.Build();

Sintassi fluente

Se ogni metodo termina con return this , puoi unirli insieme usando la sintassi fluente :

var car = new CarBuilder().WithWheels(17, WheelType.Aluminum)
                          .WithEngine(displacement: 2.1F, 
                                      cylinders:    4, 
                                      ecu:          EcuType.Programmable, 
                                      fuel:         FuelType.Unleaded)
                          .WithDoors(powerlock: true)
                          .Build();

Come fabbrica

Un'altra caratteristica di questo modello è che il metodo Build() può restituire qualsiasi classe che eredita da Car; quindi puoi estendere e specializzare la Car (ad esempio in PassengerCar, Truck, ecc.). Ciò gli consente di funzionare anche come fabbrica .

class CarBuilder()
{
    public Car Build()
    {
        Car newInstance;
        if (_wheels == 18) newInstance = new Truck()
        else if (_wheels == 4 && _powerLock) newInstance = new LuxuryCar()
        else newInstance = new PassengerCar();

        return newInstance;
    }
}
    
risposta data 01.02.2017 - 02:56
fonte
2

Ti incoraggio ad adottare un approccio più orientato ai dati invece di utilizzare un nuovo codice (nuove classi) per ogni piccola parte.

Per qualcosa di così complesso, vorrei creare un piano con le opzioni selezionate dall'utente.

I piani sono lì per garantire che un'auto utilizzabile venga fuori dall'altra parte.

I piani possono variare da semplici elenchi delle parti, non solo elencare parti ma anche acquisire dettagli di assemblaggio / assemblaggio gerarchicamente composti. Inoltre, molte opzioni di configurazione disponibili hanno regole (non compatibili con questo o quello, richiede questo o quello ...).

Esistono numerose offerte software ampie e professionali progettate per aiutare con queste cose.

Se ti interessava creare alcune di queste funzionalità in casa, ti suggerirei di creare una nozione formale di un "piano" utilizzando una qualche forma di elenco di parti generiche e regole per le varie opzioni, e quindi creare strumenti per lavorare con i piani e parti generiche.

Quindi i tuoi compiti software dovrebbero (1) supportare la creazione e la convalida dei piani, (2) presentare i piani con le loro opzioni disponibili in qualche interfaccia utente, (3) acquisire un piano base selezionato con opzioni scelte appositamente, ( 4) istanzia un ordine (o qualcos'altro) da quei piani con le opzioni scelte.

Se lo fai nel modo in cui descrivi sopra nella domanda, i tuoi piani di auto saranno catturati solo nel codice di classi specializzate (piuttosto che come informazioni che potrebbero altrimenti essere manipolate), che è quello che avremmo fare riferimento a come hardcoded ed essere un problema di manutenzione.

How do I create instances of classes which require a huge amount of components and attributes?

Non lo farei manualmente (cioè scrivendo un codice personalizzato per ogni scenario). Preferirei invece creare funzionalità generiche per istanziare ciò di cui ho bisogno dai piani scelti con le opzioni prescelte, il che mi fornirà un elenco delle parti da cui potrebbero essere fatti gli oggetti desiderati o gli ordini. (Se avessi bisogno di oggetti, avrei riutilizzato una classe di parti generiche che sarebbe stata in grado di rappresentare qualsiasi parte.)

Would this be usable if the class actually needs thousands of arguments like a real car would?

Non credo che nessuno dei modi che stai suggerendo possa funzionare per un'automobile reale, piuttosto vorresti un modo per comunicare i piani disponibili e amp; opzioni e quindi selezioni.

Also, I am never going to use any of these components (wheel, engine, transmission, etc...) in anything other than inside of a car, so why leave them outside of the scope of the car class?

Nell'industria automobilistica, le singole parti dovranno essere ordinate, acquistate, riparate, ecc ... Quindi, queste parti saranno utilizzate al di fuori della "macchina". Tuttavia, ripeto che si guarda più a catturare la nozione di piani e parti come dati piuttosto che come codice (classi).

    
risposta data 01.02.2017 - 02:25
fonte

Leggi altre domande sui tag