Quando utilizzare i metodi finali?

3

Quando voglio rendere un metodo definitivo, prima di tutto mi chiedo:

Questo metodo dovrebbe essere definitivo?

A volte la risposta è ovvia, ad esempio immagina questo:

class Dog
{
    private $name;

    public function __constructor($name)
    {
        this->name = $name;
    }

    final public function getName()
    {
        return this->name;
    }
}

Il metodo getName dovrebbe ovviamente essere definitivo.

Alcuni ragazzi chiedono perché questo è ovvio? Vedi questo esempio:

class DogsSchool
{
    private $registredDogs = [];

    final public function registerDog(Dog $dog)
    {
        this->registredDogs[$dog->getName()] = $dog;
    }
}

Se le persone cambiano il nome del cane in metodi non di costruzione, ad esempio nel metodo getName , non puoi registrare il cane in nessuna raccolta come DogsSchool , tu non è possibile identificare il cane perché l'ID (qui è il nome) può essere modificato in qualsiasi momento. questo interromperà la tua domanda. e anche nel mondo reale gli identificatori sono definitivi, puoi cambiare il tuo numero identificativo dopo la tua nascita? (nascita = costruzione in OO)

OK, nessun problema, MA! A volte mi sto confondendo! per esempio immagina questo:

class SelectMany
{
    public function selectManyAndReturn()
    {
        return selectMany();
    }
}

La sovrascrittura del metodo selectManyAndReturn può modificare il comportamento della classe, le persone possono sovrascriverla ed eseguire selectOne per esempio invece di selectMany , OK , Posso rendere questo metodo definitivo anche per prevenire questo, ma in questo modo sto anche impedendo alle persone di aggiungere nuove funzionalità al metodo, ad esempio se definisco il metodo finale, non sono in grado di scrivere una nuova classe figlia come questa uno:

class SelectManyApple extends SelectMany
{
    public function selectManyAndReturn()
    {
        return selectManyApple();
    }
}

Che cosa dovrei fare? La strategia finale e privata è completamente sbagliata? come molte applicazioni e molti linguaggi di programmazione? oppure Puoi dirmi esattamente quando dovremmo rendere un metodo definitivo?

La domanda è indipendente dal linguaggio. Riguarda il principio generale che dovrei usare per scrivere buoni programmi OO.

    
posta Sina 22.07.2017 - 20:44
fonte

1 risposta

12

Se stai distribuendo il codice al pubblico, rendi definitive le tue classi e i tuoi metodi, a meno che la classe o il metodo non sia specificamente progettato per essere sovrascritto o ereditato.

Quando dovresti creare una classe o un metodo final ? Quando non si desidera che un utente della classe (ovvero un'entità con cui non è possibile applicare le politiche) lo sovrascriva. Crea una classe final quando non desideri che un utente erediti da esso.

Ovviamente, questo solleva solo la domanda "quando potresti non vuoi che un utente esegua l'override o l'ereditarietà?" In qualsiasi progetto non banale, quasi sempre. In .NET Framework, le classi sono sealed per impostazione predefinita.

Il motivo è semplice: se un utente esegue l'override o l'ereditarietà, non hai idea di come prevedere cosa potrebbe fare l'utente con la tua classe o metodo, né puoi fornire alcuna garanzia che le loro azioni non rompere la tua classe, il tuo metodo o qualche altra parte del sistema.

Per dirla in altro modo, a meno che tu non controlli attentamente come viene utilizzata la tua classe, non puoi fornire garanzie ragionevoli che funzioni in tutti i casi. Rendendo definitive le tue classi e i tuoi metodi, puoi controllare il comportamento di finale di loro, e quindi puoi rendere dichiarazioni sul comportamento delle tue classi / metodi con un ragionevole grado di certezza, senza doversi preoccupare di qualcuno che modifica il comportamento della tua classe o metodo in modi che non hai previsto.

Quindi la domanda diventa, quando dovrei consentire a un utente di sovrascrivere?

Quando hai progettato il metodo e / o la classe in modo che sia sovrascrivibile in modo coerente con la progettazione della classe.

Alcuni metodi devono essere sovrascritti. Il metodo ToString() è quasi sempre sovrascrivibile nella maggior parte dei moderni linguaggi OO perché è semplicemente un output, in genere visualizzato solo, e per molti oggetti restituisce un risultato predefinito che non è particolarmente significativo in ogni caso.

Un'eccezione che dimostra che la regola è i metodi Linq. I metodi Linq sono metodi di estensione, un meccanismo in C # che consente allo sviluppatore di "puntare saldare" metodi arbitrari su un tipo. Il motivo per cui funziona senza rompere le cose è perché il metodo di estensione non ha accesso agli interni della classe che sta modificando, ma solo ai suoi membri pubblici.

    
risposta data 22.07.2017 - 21:47
fonte

Leggi altre domande sui tag