JavaRush /Java Blog /Random-IT /Principi OOP

Principi OOP

Pubblicato nel gruppo Random-IT
Ciao! Ti sei mai chiesto perché Java è progettato così com'è? Nel senso che crei classi, basate su di esse: oggetti, classi hanno metodi, ecc. Ma perché la struttura del linguaggio è tale che i programmi sono costituiti da classi e oggetti e non da qualcos'altro? Perché è stato inventato e messo in primo piano il concetto di “oggetto”? Tutte le lingue funzionano in questo modo e, in caso contrario, quali vantaggi offre Java? Come puoi vedere, ci sono molte domande :) Proviamo a rispondere a ciascuna di esse nella lezione di oggi.

Principi OOP:

  1. Eredità
  2. Astrazione
  3. Incapsulamento
  4. Polimorfismo

Cos'è la programmazione orientata agli oggetti (OOP)

Naturalmente Java è composto da oggetti e classi per un motivo. Questo non è un capriccio dei suoi creatori, e nemmeno una loro invenzione. Esistono molti altri linguaggi basati su oggetti. Il primo di questi linguaggi si chiamava Simula ed è stato inventato negli anni '60 in Norvegia. Tra le altre cose, Simula ha introdotto i concetti di “ classe ” e “ metodo ”. Principi di programmazione orientata agli oggetti - 2
Kristen Nygaard e Ole Johan Dahl - creatori di Simula
Sembrerebbe che Simula sia un linguaggio antico secondo gli standard di programmazione, ma la loro connessione "familiare" con Java è visibile ad occhio nudo. Molto probabilmente, puoi leggere facilmente il codice scritto su di esso e spiegare in termini generali cosa fa :)
Begin
  Class Rectangle (Width, Height); Real Width, Height;

   Begin
      Real Area, Perimeter;

      Procedure Update;
      Begin
        Area := Width * Height;
              OutText("Rectangle is updating, Area = "); OutFix(Area,2,8); OutImage;
        Perimeter := 2*(Width + Height);
              OutText("Rectangle is updating, Perimeter = "); OutFix(Perimeter,2,8); OutImage;
      End of Update;

      Update;
      OutText("Rectangle created: "); OutFix(Width,2,6);
      OutFix(Height,2,6); OutImage;
   End of Rectangle;

       Rectangle Class ColouredRectangle (Color); Text Color;

  Begin
      OutText("ColouredRectangle created, color = "); OutText(Color);
      OutImage;
        End of ColouredRectangle;


         Ref(Rectangle) Cr;
   Cr :- New ColouredRectangle(10, 20, "Green");
End;
L'esempio di codice è tratto dall'articolo Simula - 50 anni di OOP . Come puoi vedere, Java e il suo antenato non sono così diversi l'uno dall'altro :) Ciò è dovuto al fatto che l'apparizione di Simula ha segnato la nascita di un nuovo concetto: la programmazione orientata agli oggetti. Wikipedia fornisce la seguente definizione di OOP: La programmazione orientata agli oggetti (OOP) è una metodologia di programmazione basata sulla rappresentazione di un programma come una raccolta di oggetti, ciascuno dei quali è un'istanza di una classe specifica, e le classi formano una gerarchia di ereditarietà. Secondo me ha molto successo. Di recente hai iniziato a imparare Java, ma difficilmente ci sono parole che non ti sono familiari :) Oggi, l'OOP è la metodologia di programmazione più comune. Oltre a Java, i principi OOP sono utilizzati in molti linguaggi popolari di cui potresti aver sentito parlare. Questi sono C++ (viene utilizzato attivamente dagli sviluppatori di giochi per computer), Objective-C e Swift (scrivono programmi per dispositivi Apple), Python (più richiesto nell'apprendimento automatico), PHP (uno dei linguaggi di sviluppo web più popolari), JavaScript (è più semplice dire cosa non fanno su di esso) e molti altri. In realtà, quali sono questi “principi” dell’OOP? Te lo diciamo più in dettaglio.

Principi OOP

Queste sono le basi. 4 caratteristiche principali che insieme formano il paradigma della programmazione orientata agli oggetti. Comprenderli è la chiave per diventare un programmatore di successo. Principi di programmazione orientata agli oggetti - 3

Principio 1. Eredità

La buona notizia è che conosci già alcuni dei principi dell'OOP! :) Abbiamo già incontrato l'ereditarietà un paio di volte durante le lezioni e abbiamo avuto il tempo di lavorarci. L'ereditarietà è un meccanismo che consente di descrivere una nuova classe basata su una classe esistente (genitore). In questo caso, le proprietà e le funzionalità della classe genitore vengono prese in prestito dalla nuova classe. Perché è necessaria l’eredità e quali vantaggi offre? Prima di tutto, il riutilizzo del codice. I campi e i metodi descritti nelle classi madri possono essere utilizzati nelle classi discendenti. Se tutti i tipi di auto hanno 10 campi comuni e 5 metodi identici, devi solo inserirli nella classe genitore Auto. Puoi usarli nelle classi discendenti senza problemi. Solidi vantaggi: sia quantitativamente (meno codice) che, di conseguenza, qualitativamente (le classi diventano molto più semplici). Allo stesso tempo, il meccanismo di ereditarietà è molto flessibile ed è possibile aggiungere separatamente le funzionalità mancanti nei discendenti (alcuni campi o comportamenti specifici di una particolare classe). In generale, come nella vita ordinaria: siamo tutti simili ai nostri genitori in qualche modo, ma in qualche modo diversi da loro :)

Principio 2. Astrazione

Questo è un principio molto semplice. Astrazione significa evidenziare le caratteristiche principali e più significative di un oggetto e viceversa, scartando quelle secondarie e insignificanti. Non reinventiamo la ruota e ricordiamo un esempio tratto da una vecchia lezione sulle lezioni. Diciamo che stiamo creando uno schedario dei dipendenti dell'azienda. Per creare oggetti dipendente, abbiamo scritto una classe Employee. Quali caratteristiche sono importanti per la loro descrizione nella scheda aziendale? Nome completo, data di nascita, codice fiscale, codice fiscale. Ma è improbabile che in una carta di questo tipo servano la sua altezza, il colore degli occhi e dei capelli. L'azienda non ha bisogno di queste informazioni sul dipendente. Pertanto, per la classe Employeeimposteremo le variabili String name, int age, int socialInsuranceNumbere int taxNumber, e abbandoneremo le informazioni che non ci sono necessarie, come il colore degli occhi, e le astraremo. Ma se creiamo un catalogo di fotomodelle per un'agenzia, la situazione cambia radicalmente. Per descrivere una modella, per noi sono molto importanti l'altezza, il colore degli occhi e il colore dei capelli, ma non è necessario il numero TIN. Pertanto, nella classe Modelcreiamo le variabili String height, String hair, String eyes.

Principio 3: incapsulamento

Lo abbiamo già incontrato. L'incapsulamento in Java significa limitare l'accesso ai dati e la possibilità di modificarli. Come puoi vedere, si basa sulla parola “capsula”. In questa “capsula” nascondiamo alcuni dati per noi importanti che non vogliamo che nessuno cambi. Un semplice esempio dalla vita. Hai un nome e un cognome. Tutti quelli che conosci li conoscono. Ma non hanno accesso per cambiare il tuo nome e cognome. Questo processo, si potrebbe dire, è "incapsulato" nell'ufficio passaporti: lì puoi cambiare solo nome e cognome, e solo tu puoi farlo. Altri "utenti" hanno accesso in sola lettura al tuo nome e cognome :) Un altro esempio sono i soldi nel tuo appartamento. Lasciarli in bella vista al centro della stanza non è una buona idea. Qualsiasi “utente” (una persona che viene a casa tua) potrà modificare il numero dei tuoi soldi, ad es. prendili. È meglio incapsularli in una cassaforte. Solo tu avrai accesso e solo con un codice speciale. Esempi evidenti di incapsulamento con cui hai già lavorato sono i modificatori di accesso ( private, publicecc.) e i getter-setter. Se il campo agedella classe Catnon è incapsulato, chiunque può scrivere:
Cat.age = -1000;
E il meccanismo di incapsulamento ci permette di proteggere il campo agecon un metodo setter, in cui possiamo verificare che l'età non possa essere un numero negativo.

Principio 4. Polimorfismo

Il polimorfismo è la capacità di trattare più tipi come se fossero dello stesso tipo. In questo caso il comportamento degli oggetti sarà diverso a seconda della tipologia a cui appartengono. Sembra un po' complicato? Scopriamolo adesso. Prendiamo l'esempio più semplice: gli animali. Creiamo una classe Animalcon un singolo metodo - voice()e due dei suoi discendenti - Cate Dog.
public class Animal {

   public void voice() {

       System.out.println("Voice!");
   }
}

public class Dog extends Animal {


   @Override
   public void voice() {
       System.out.println("Bow-wow!");
   }
}

public class Cat extends Animal {

   @Override
   public void voice() {
       System.out.println("Meow!");
   }
}
Ora proviamo a creare un collegamento Animale ad assegnargli un oggetto Dog.
public class Main {

   public static void main(String[] args) {

       Animal dog = new Dog();
       dog.voice();
   }
}
Quale metodo pensi che verrà chiamato? Animal.voice()O Dog.voice()? Il metodo della classe si chiamerà Dog: Woof-woof! Abbiamo creato un riferimento Animal, ma l'oggetto si comporta come Dog. Se necessario, può comportarsi come un gatto, un cavallo o un altro animale. La cosa principale è assegnare un riferimento di tipo generale Animala un oggetto di una specifica classe discendente. Questo è logico, perché tutti i cani sono animali. Questo è ciò che intendevamo quando abbiamo detto “gli oggetti si comporteranno in modo diverso a seconda del tipo che sono”. Se dovessimo creare un oggetto Cat
public static void main(String[] args) {

   Animal cat = new Cat();
   cat.voice();
}
il metodo voice()produrrebbe "Meow!" Cosa significa “la capacità di lavorare con più tipi come se fossero lo stesso tipo”? Anche questo è abbastanza facile. Immaginiamo di creare un parrucchiere per animali. Il nostro parrucchiere deve essere in grado di tagliare tutti gli animali, quindi creeremo un metodo shear()(“taglio”) con un parametro Animal: l'animale che taglieremo.
public class AnimalBarbershop {

   public void shear(Animal animal) {

       System.out.println("The haircut is ready!");
   }
}
E ora possiamo passare shearsia gli oggetti Catche gli oggetti al metodo Dog!
public static void main(String[] args) {

   Cat cat = new Cat();
   Dog dog = new Dog();

   AnimalBarbershop barbershop = new AnimalBarbershop();

   barbershop.shear(cat);
   barbershop.shear(dog);
}
Ecco un chiaro esempio: la classe AnimalBarbershoplavora con i tipi Catcome Dogse fossero dello stesso tipo. Allo stesso tempo, hanno comportamenti Catdiversi Dog: usano la voce in modo diverso.

Ragioni per la comparsa di OOP

Perché è nato questo nuovo concetto di programmazione - OOP - ? I programmatori avevano strumenti che funzionavano: linguaggi procedurali, per esempio. Cosa li ha spinti a inventare qualcosa di fondamentalmente nuovo? Innanzitutto la complicazione dei compiti che dovevano affrontare. Se 60 anni fa il compito di un programmatore era "calcolare un'equazione matematica così e così", ora potrebbe sembrare come "implementare 7 finali diversi per il gioco STALKER a seconda delle decisioni prese dall'utente nei momenti di gioco A, B, C, D" , E, F e combinazioni di queste soluzioni." Come potete vedere, negli ultimi decenni i compiti sono chiaramente diventati più complessi. Ciò significa che i tipi di dati sono diventati più complessi. Questo è un altro motivo per l'emergere dell'OOP. L'esempio con l'equazione può essere facilmente risolto utilizzando le primitive ordinarie; qui non sono necessari oggetti. Ma sarà difficile anche solo descrivere il problema dei finali del gioco senza utilizzare alcune classi che hai inventato. Ma allo stesso tempo è abbastanza semplice descriverlo in classi e oggetti: avremo ovviamente bisogno della classe Game, della classe Stalker, della classe Ending, della classe Player’s Decision, della classe Game Moment e così via. Cioè, anche senza iniziare a risolvere un problema, possiamo facilmente immaginare nella nostra testa “schizzi” della sua soluzione. La crescente complessità dei problemi ha costretto i programmatori a dividere il problema in parti. Ma nella programmazione procedurale ciò non era così semplice. E molto spesso il programma era un "albero" formato da un mucchio di rami con tutte le opzioni possibili per il suo funzionamento. A seconda di determinate condizioni, il programma veniva eseguito lungo un ramo o l'altro. Per i piccoli programmi questa opzione era conveniente, ma dividere un'attività di grandi dimensioni in parti era molto difficile. Questa esigenza è diventata un'altra ragione per l'emergere dell'OOP. Questo concetto dava ai programmatori la possibilità di dividere un programma in un gruppo di “moduli” di classi, ognuna delle quali svolgeva la propria parte di lavoro. Tutti gli oggetti, interagendo tra loro, formano il lavoro del nostro programma. Inoltre, il codice che scriviamo può essere riutilizzato altrove nel programma, il che fa risparmiare anche molto tempo.
Commenti
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION