Domanda

Ho appena trovato questa citazione in un libro su OOP che sto leggendo,

  

A un bambino è consentito solo aumentare   funzionalità e aggiungere funzionalità.   Un bambino non è mai autorizzato a rimuovere   funzionalità. Se lo trovi a   il bambino deve rimuovere la funzionalità,   questa è un'indicazione che il bambino   dovrebbe apparire prima del genitore nel file   gerarchia ereditaria!

Ma la mia domanda è: non è questo ciò che ha la precedenza?

È stato utile?

Soluzione

Puoi rimuovere la funzionalità con l'override. Ma normalmente lo usi per cambiare il comportamento. Per consentire alla classe di comportarsi come dovrebbe essere.

Se il comportamento viene rimosso, molto spesso è un segno di un cattivo design della classe.

Altri suggerimenti

Il bambino non può rimuovere la funzionalità: può alterarla, ma non è possibile, ad esempio, rendere privato un metodo pubblico.

Il punto di eredità è che puoi gestire il figlio come se fosse il genitore. Se hai una superclasse "Persona" una sottoclasse "Dipendente", non avrebbe senso per la classe Employee non avere il metodo respirate ().

Quando si esegue l'override di un metodo, è possibile chiamare l'implementazione padre in qualche momento durante l'override, quindi utilizzare l'override per aggiungere funzionalità all'implementazione padre.

No. In realtà aumenteresti la funzionalità (in modo negativo)

Supponiamo che la tua nuova funzionalità sia " non fare nulla " ma il metodo, ciò che i client del tuo codice vedono è sempre lo stesso interfaccia

Non puoi avere una sottoclasse che rimuova un metodo dal suo genitore.

Questo è possibile

class Parent {
    public void method_one(){ 
        print "Hello";
    }
}

class Child extends Parent {
     public void method_one(){
         // do nothing
     }
 }

Ma questo non è:

class Parent {
    public void method_one(){ 
        print "Hello";
    }
}

class Child extends Parent {
     // Attempt remove the method visibility, thus remove funcionality 
     private void method_one(){ 
         // do nothing
     }
 }

Ed è per questo che l'override (e in generale, qualsiasi membro virtuale) è qualcosa che dovrebbe essere fatto con molta attenzione ... In effetti, in genere, quando si esegue l'override, è necessario provare a codificare sia la classe base che la classe derivata, in modo che l'implementazione della classe derivata prima chiami l'implementazione di base, quindi esegua la sua funzionalità aggiuntiva ...

ma questo principio non è applicato nelle lingue OO ed è spesso violato ...

Esempio del perché questo è negativo

Immagina di avere un tipo di telefono CompanyA (classe) disegni

namespace CompanyA {
   class Phone {
       public void Dial() {
        // do work to dial the phone here
       }
   }
}

Nessun iagine Azienda B definisce un altro tipo di BetterPhone, che utilizza il Telefono dell'azienda A come tipo di base ...

namespace CompanyB {
   class BetterPhone: CompanyA.Phone {
       public void Dial()  {
           Console.WriteLine("BetterPhoneDial");
           EstablishConenction();
           base.Dial();
       }
   }
}

Ora CompanyA, la cui classe Phone è in uso da altre società (Company C, D, ecc.) decide che stabilire una connessione è una cosa utile da avere nella classe, e modifica CompanyA.Phone, aggiungendo un EsatblishCOnnection () anche metodo, forse con un'implementazione diversa ... Fino a quando non avremmo avuto il "nuovo" parola chiave, questo scenario avrebbe spezzato la classe BetterPhone di CompanyB ... la prima volta che hanno tentato di utilizzare la nuova classe di base.

Se tuo figlio richiede di rimuovere la funzionalità di genitore, allora genitore deve essere dichiarato come interfaccia. Perché Interface è un meccanismo che definisce i contratti che devono essere rispettati dal suo implementatore.

es.


public interface IContract
{
  void DoWork();
}

public class BaseContract: IContract
{
 public virtual void DoWork()
 {
  //perform operation A
 }
}

Ora, se si desidera dichiarare la nuova classe EnhancedContract, è possibile derivarla da BaseContract o IContract in base ai requisiti. Se desideri eseguire un'operazione aggiuntiva sull'operazione A di base, puoi ereditarla da BaseContract come mostrato di seguito.


public class EnhancedContract: BaseContract
{
  public override void DoWork()
  {
   //perform operation B
   base.DoWork();
   //perform operation C
  }
}

Ma se non sei interessato a eseguire l'operazione A nel metodo DoWork di EnhancedContract, ereditalo da IContract.

Ciò assicura che EnhancedWork eseguirà DoWork (), ma non è garantito che esegua "l'operazione A" al suo interno.


public class EnhancedWork:IContract
{
  public void DoWork()
  {
   //perform operation D
  }
}

Questo è importante per il sottotitolo perché impedirà all'utente di fare il casting sotto.


EnhancedContract e = new EnhancedContract();
BaseContract b = e;

Credo che tutte queste operazioni siano importanti per comprendere Principio di apertura chiuso , Principio di sostituzione di Liskov .

La regola del pollice per l'ereditarietà è " Inserisci funzionalità aggiuntiva in una esistente " ;.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top