Progetto di dominio di classe attivo o passivo [chiuso]

1

Scusa se il mio esempio (semplificato) è troppo ampio.

Dato questo modello (scritto in C #):

class Ball
{
}

Supponiamo che una palla possa essere lanciata.

Per implementare questa funzione, posso definire qualcosa come:

class Ball
{
    void Launch();
}

o qualcosa di simile:

class BallLauncher
{
    void Launch(Ball ball);
}

In quali situazioni è meglio usare il primo approccio e quale il secondo?

In realtà, questo esempio cerca di semplificare un modello reale reale sottostante. In quel modello, ho bisogno di caricare file ( Package ) in un repository.

Quindi, non so se il repository dovrebbe caricare (copia fisica) un pacchetto (file) su se stesso o è il pacchetto che dovrebbe caricarsi su un repository.

    
posta HuorSwords 29.07.2014 - 11:57
fonte

2 risposte

4

Esempio di base: lancio di una palla

Analizzare gli aiuti della logica aziendale. La palla può forse lanciarsi da sola? Probabilmente no. È solo una palla e non può muoversi da sola. Ciò significa che dovrai creare un BallLauncher per avviarlo.

Cosa dovrebbe contenere Ball class? Principalmente proprietà dell'oggetto, come raggio, colore e consistenza.

Esempio di due oggetti: lancia un razzo

A Rocket può essere lanciato da solo, o può richiedere un launcher. A volte, guardando la logica, potrebbe non essere ovvio dove mettere il metodo. Un missile non è passivo, ma potrebbe aver bisogno di un lanciatore. È necessario un lanciatore per lanciare un razzo, ma il razzo partecipa anche al lancio.

Quando la logica non è ovvia, ecco un suggerimento: implementa il metodo Launch e osserva come vengono utilizzati Rocket e Launcher .

Esempio:

class Rocket
{
    public void Launch()
    {
        this.ControlTower.RequestTakeoff().WhenAuthorized(launcher =>
        {
            launcher.Prepare();
            if (launcher.Status == LauncherStatus.ReadyForLaunch)
            {
                launcher.Launch();
                launcher.PrepareNewRocket();
            }
            else
            {
                throw new BrokenLauncherException();
            }
        });
    }
}

sovrascrive su Launcher e deve essere spostato su Launcher class. D'altra parte:

class Launcher
{
    public void Launch(Rocket rocket)
    {
        rocket.Ignite();
        rocket.IncreasePressureTo(Rocket.RecommendedPressureOnLaunch);
        rocket.PrepareForTakeoff();
        if (rocket.IsReady)
        {
            this.Release();
            rocket.Takeoff();
        }
        else
        {
            rocket.CancelTakeoff();
            rocket.Engines.ShutDownEmergency();
            throw new BrokenRocketException();
        }
    }
}

è un metodo illustrativo che si trova in una classe sbagliata: dovrebbe essere spostato su Rocket .

Esempio di tre oggetti: pacchetto, repository, uploader

Allo stesso modo, se hai Package e Repository :

  • Il pacchetto deve essere caricato su un repository,
  • Se un repository carica un pacchetto su se stesso,
  • O dovrebbe esserci un Uploader che si occupa di pacchetti e repository attraverso Upload(package, repository) ?

Ancora una volta, prevale la logica aziendale e, come nell'esempio precedente, può essere d'aiuto osservare come Package e Repository siano usati all'interno del metodo.

  • Se Upload sovrascrive su Package , potrebbe essere un suggerimento che dovrebbe essere Package.Upload .

  • Se Upload chiama i metodi da Repository praticamente sempre, spostalo su Repository .

  • Se Upload ha una logica che semplicemente non si adatta a Package o Repository , questa è una buona opportunità per creare un Uploader .

risposta data 29.07.2014 - 12:03
fonte
1

Da una prospettiva OO, se Launch() implica la mutazione dello stato interno della Sfera, preferirei il primo design.

Una buona pratica in OO è il Tell, Do not Ask principle :

you should endeavor to tell objects what you want them to do; do not ask them questions about their state, make a decision, and then tell them what to do

È probabile che Launch(Ball ball) chiederà cose dalla Palla e poi agirà basandosi su questo, cambiando il suo stato, mentre Ball.Launch() manterrà tutto ben incapsulato in esso.

Il caso in cui vedo una firma Launch(Ball ball) è un senso se si desidera delegare l'istanziazione di una sfera a un codice esterno e quindi iniettare quella sfera nel Launcher come dipendenza a livello di metodo. Ma il Launcher probabilmente dovrebbe comunque chiamare qualcosa come Ball.Launch() .

    
risposta data 29.07.2014 - 13:20
fonte

Leggi altre domande sui tag