Sta sovraccaricando un esempio del principio Aperto / Chiuso?

12

Wikipedia dice

"software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification"

La parola funzioni ha attirato la mia attenzione e ora mi chiedo se possiamo pensare che la creazione di un sovraccarico per un metodo possa essere considerato un esempio del principio Aperto / chiuso o no?

Lasciatemi spiegare un esempio. Considera che hai un metodo nel tuo livello di servizio, che viene utilizzato in quasi 1000 posizioni. Il metodo ottiene userId e determina se l'utente è admin o meno:

bool IsAdmin(userId)

Consideriamo ora che da qualche parte è necessario determinare se l'utente è admin o meno, in base al nome utente, non a userId. Se cambiamo la firma del metodo sopra menzionato, abbiamo interrotto il codice in 1000 punti (le funzioni dovrebbero essere chiuse alla modifica). Quindi possiamo creare un sovraccarico per ottenere il nome utente, trovare l'ID utente in base al nome utente e il metodo originale:

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

In questo modo, abbiamo esteso la nostra funzione creando un sovraccarico (le funzioni dovrebbero essere aperte all'estensione).

È un esempio di principio aperto / chiuso?

    
posta Saeed Neamati 09.05.2012 - 09:22
fonte

5 risposte

4

Personalmente interpreterò la dichiarazione della wiki:

  • per una classe: sentiti libero di ereditare la classe e sovrascrivi o estendi la sua funzionalità, ma non modificare la classe originale e quindi modificare ciò che fa.
  • per un modulo (forse una libreria per istanza): sentiti libero di scrivere un nuovo modulo / libreria che avvolge il originale, unisce le funzioni in versioni più facili da usare o estende l'originale con funzioni aggiuntive, ma non cambia l'originale modulo.
  • per una funzione (cioè una funzione statica, non un metodo di classe): il tuo esempio è ragionevole per me; riutilizzare l'IsAdmin originale (int) funzione all'interno del nuovo IsAdmin (stringa). l'originale no cambia, la nuova funzione estende la sua funzionalità.

lo scatto nel piede tuttavia è che se il tuo codice utilizza la classe 'cUserInfo' in cui risiede IsAdmin (int), stai essenzialmente infrangendo la regola e modificando la classe. purtroppo la regola verrà mantenuta solo se hai creato una nuova classe cUserWithNameInfo: public cUserInfo e metti la tua IsAdmin (stringa) in override. Se possedessi il codice base non obbedirei mai alla regola. Direi bollock e apporta solo il resto che suggerisci.

    
risposta data 09.05.2012 - 10:15
fonte
3

Prima di tutto, il tuo esempio è sfortunatamente ideato. Non lo faresti mai nel mondo reale, perché provoca un inutile raddoppio. O, peggio, perché userid e username potrebbero diventare lo stesso tipo ad un certo punto. Piuttosto che

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUser(userid);
    return user.IsAdmin();
}

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

Dovresti davvero estendere quella classe.

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUserById(userid);
    return user.IsAdmin();
}

public bool IsUsernameAdmin(string username)
{
    User userId = UserManager.GetUserByName(username);
    return user.IsAdmin();
}

Potresti refactoring e cambiare il nome del primo metodo in IsUserIdAdmin, per coerenza, ma non è necessario. Il punto è che, aggiungendo il nuovo metodo e garantendo che nessun codice di chiamata sia rotto, hai trovato la tua classe estendibile. O in altre parole, aperto all'estensione .

Ed ecco la cosa con il principio open-closed. Non sai mai sapere quanto bene il tuo codice è conforme fino a quando non provi a estenderne una parte e ti trovi a dover modificare (con l'aumento del rischio che ne deriva). Ma, con l'esperienza, impari a prevedere.

Come dice lo zio Bob (sottolineatura mia):

Since closure cannot be complete, it must be strategic. That is, the designer must choose the kinds of changes against which to close his design. This takes a certain amount of prescience derived from experience. The experienced designer knows the users and the industry well enough to judge the probability of different kinds of changes. He then makes sure that the open-closed principle is invoked for the most probable changes.

    
risposta data 09.05.2012 - 12:26
fonte
2

Modules that conform to the open-closed principle have two primary attributes.

  1. They are “Open For Extension”. This means that the behavior of the module can be extended. That we can make the module behave in new and different ways as the requirements of the application change, or to meet the needs of new applications.
  2. They are “Closed for Modification”. The source code of such a module is inviolate. No one is allowed to make source code changes to it.
  1. Sovraccaricando il tuo metodo estendi le funzionalità del modulo esistente, soddisfacendo così le nuove esigenze della tua applicazione

  2. Non stai apportando modifiche a un metodo esistente, quindi non stai violando la seconda regola.

Sarei interessato a sentire cosa hanno da dire gli altri riguardo a non permettere di cambiare il metodo originale. Sì, puoi inserire i modificatori di accesso appropriati e applicare l'incapsulamento, ma che altro può essere fatto?

Rif: link

    
risposta data 09.05.2012 - 10:31
fonte
1

Il principio aperto-chiuso è un obiettivo, un caso ideale, non sempre una realtà. In particolare, quando si cerca di ridefinire il vecchio codice, il primo passo è spesso una modifica pesante per rendere possibile l'OCP. La radice del principio è che il codice funzionante funziona già, e il cambiamento probabilmente introduce dei bug. Pertanto, lo scenario migliore non è quello di modificare il codice esistente, ma solo di aggiungere un nuovo codice.

Supponiamo che tu abbia una funzione chiamata BigContrivedMethod(int1, int2, string1) . BigContrivedMethod fa tre cose: thing1, thing2 e thing3. A questo punto, riutilizzare BCM è probabilmente difficile, perché fa troppo. Refactoring (se possibile) in ContrivedFunction1(int) , ContrivedFunction2(int) e ContrivedFunction3(string) ti offre tre metodi più piccoli e più mirati che puoi combinare più facilmente.

E questa è la chiave per l'OCP in merito a metodi / funzioni: composizione. Si "estendono" le funzioni chiamandole da altre funzioni.

Ricorda che l'OCP è parte di altri 5 principi, le linee guida SOLID. Quella prima è la chiave, la singola responsabilità. Se tutto nella tua base di codice ha fatto solo la cosa specifica che doveva fare, non avresti mai avuto bisogno di modificare il codice. Dovresti solo aggiungere un nuovo codice o combinare il vecchio codice in modi nuovi. Poiché il codice reale raramente soddisfa tale linea guida, è spesso necessario modificarlo per ottenere SRP prima di poter ottenere l'OCP.

    
risposta data 09.05.2012 - 15:19
fonte
0

Stai seguendo il principio di open-closed se stai modificando il comportamento del tuo programma scrivendo un nuovo codice piuttosto che alterando il vecchio codice.

Dato che è praticamente impossibile scrivere codice aperto a tutte le possibili modifiche (e non lo si vuole perché si entra nella paralisi dell'analisi) si scrive codice che risponde a tutti i diversi comportamenti a cui si sta lavorando per estensione piuttosto che di modifica.

Quando ti imbatti in qualcosa che devi cambiare, invece di limitarti a modificare qualcosa per consentire il nuovo comportamento, puoi capire qual è il punto di cambiamento, ristrutturare il tuo programma senza alterarne il comportamento in modo da poter cambiare quel comportamento scrivendo NUOVO codice.

Quindi, come si applica al tuo caso:

Se aggiungi nuove funzioni alla tua classe, la tua classe non è aperta / chiusa ma i client della funzione che stai sovraccaricando.

Se stai semplicemente aggiungendo nuove funzioni che funzionano sulla tua classe, allora sia essa che i client della tua funzione sono aperti / chiusi.

    
risposta data 09.05.2012 - 20:47
fonte

Leggi altre domande sui tag