Sunteți pe pagina 1din 63

PROGRAMARE ORIENTATĂ

OBIECT
Limbajul şi platforma Java
Programare II. C2
Motto
“Simple can be harder than complex: You have to work
hard to get your thinking clean to make it simple. But it’s
worth it in the end because once you get there, you can
move mountains.”
Steve Jobs [BusinessWeek, May 25, 1998,]

2
Capitolul 2.
Principii ale ORIENTĂRII OBIECTUALE

Încapsulare și abstractizare. Compunere și moștenire


Agenda: Principii OO
❏ 1. Ascunderea informației și abstractizare
❏ Încapsulare
❏ Interfețe și implementare
❏ 2. Reutilizabilitatea obiectelor și claselor prin
compunere și moștenire
❏ Compunerea obiectelor
❏ Specializarea claselor

4
1. Principiul ascunderii informației și abstractizării
● Ascunderea informației: separarea implementării
interne față de reprezentarea externă.
● Ascunderea informației sau încapsularea (prin
specificatorii de vizibilitate):
○ încapsularea atributelor;
○ încapsularea comportamentală;
○ împachetarea claselor.
● Abstractizarea: separarea reprezentării externe față
de implementarea internă.
● Abstractizarea prin interfețe: separarea definiției
abstracte față de implementare.

5
1.1 Principiul ascunderii informaţiei
❏ Ascunderea informației reprezintă un mecanism de
încapsulare (delimitare sau separare)
❏ a detaliilor interne (private)
❏ față de caracteristicile accesibile extern (publice) ale
obiectelor.

❏ Principiul ascunderii informaţiei se referă la protejarea


caracteristicilor interne ale obiectelor astfel ca doar
acele detalii structurale (informaţionale) și
comportamentale relevante ale unui obiect să fie
accesibile în contextul în care sunt folosite (instanţiate,
referenţiate).

6
Specificatorii de vizibilitate în Java
❏ Specificatori pentru îngrădirea (protejarea) accesului din
contextul (client) în care va fi invocat obiectul:
❏ private - încapsulare completa;
❏ “package” sau “friendly” - fără specificator explicit:
restricționează accesul din clase din pachete externe;
❏ protected restricționează accesul din pachete externe din
afara ierarhiei de moștenire.
❏ Specificatori pentru pemiterea accesului (la membrii
structurii de atribute și operații) din contextul (client) în
care va fi invocat obiectul:
❏ public - deschidere completă;
❏ “friendly” sau “package” - fără specificator explicit: permite
accessul din clase din același pachet.
❏ protected - extinde vizibilitatea package la subclase din
pachete externe.
7
Specificatorii de vizibilitate Java
Creștere încapsularea

Vizibilitate public protected (package) private

Din aceeași clasă Da Da Da Da

Dintr-o clasă din același pachet Da Da Da Nu

Dintr-o sub-clasă din același pachet Da Da Da Nu

Dintr-o sub-clasă din afara pachetului gazdă Da Da* Nu Nu

Dintr-o non-sub-clasă din afara pachetului gazdă Da Nu Nu Nu

Creștere vizibilitatea

* Prin mecanismul de moștenire (referința super)

8
Încapsularea ATRIBUTELOR
Încapsulare structurală
❏ Se referă la protejarea detaliilor informaţionale interne
reprezentate prin atribute și controlul accesibilității
acestora prin intermediul proprietăţilor (convenţia
JavaBeans):
❏ declararea private a atributelor sau variabilelor de
instanță;
❏ restricționarea citirii atributelor prin metode accesor
sau get-teri: getNumeProprietate;
❏ restricționarea modificării atributelor prin metode
modificator sau set-teri: setNumeProprietate.

❏ Proprietățile convenționale JavaBeans permit


“exprimarea/formalizarea” conceptului de tip abstract de
date în limbajul Java.
9
De ce ar fi nevoie de metode de access/accesori?
❏ Structura “interna” unui obiect ar trebui sa ramână
internă: accesibilă direct doar “în cadrul” obiectului:
❏ atributele interne invocate prin this.atribut.
❏ Prin stabilirea unui getter se poate decide:
❏ dacă valoarea unui atribut ar putea fi “citită”;
❏ cum ar putea fi citită valoarea unui atribut (prin ce tip
de date sau în ce format);
❏ Prin stabilirea unui setter se poate decide:
❏ dacă valoarea unui atribut ar putea fi modificată de
alte obiecte.
❏ Inexistenta unui setter poate semnifica faptul că
respectivul atribut este considerat imuabil
(imutabil/nemodificabil).
10
Strategii pentru gestionarea încapsulării
atributelor în clase JavaBeans sau pentru date
● Generare metode JavaBean folosind opțiunile din IDE
(de ex. acțiunea Code/Generate… în IntelliJ).
● Folosirea tipului de clase Record, disponibil în Java 21.
● Folosirea cadrului de lucru Lombok pentru adnotarea
claselor.

11
Tipul de clase Record (Java 14>)
● Declară câmpurile încapsulate într-o clasă JavaBean
prin declarația Record - constructor canonic.
● Generează metode de accesare pentru fiecare câmp
din constructorul canonic - cu numele câmpului() -
fără particula get.
● Generează metodele standard equals(), hashCode(),
toString() pe baza câmpurilor din constructorul canonic,
dar care pot fi suprascrise.
● Obiectele instanțiate dintr-o clasă Record sunt
imutabile: câmpurile sunt înregistrate ca final-e,
metodele de access sunt doar pentru citire.

12
Exemplu simplu Record
public record CerintaRecord (
Integer idCerinta,
String denumire,
String descriere,
Long durataEstimata,
Date dataEstimata)
{
public CerintaRecord(Integer idCerinta, String
denumire, String descriere) {
this(idCerinta, denumire, descriere,
0l, new Date()); }
}

13
Cadrul de lucru Lombok
● Funcție de tipul adnotărilor adăugă (la momentul
compilării) :
○ metode accessor (getteri și setteri);
○ metodele standard: equals(), hashCode(), toString();
○ metode constructor.
● Adnotările standard pentru controlul procesului de
generare:
○ @Data - cea mai cuprinzătoare - și @Value;
○ @Getter, @Setter;
○ @EqualsAndHashCode și @ToString;
○ @NoArgsConstructor, @RequiredArgsConstructor,
@AllArgsConstructor

14
Exemplu simplu Lombok
(import lombok.*)
@Data @EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class CerintaData {
@EqualsAndHashCode.Include
private Integer idCerinta;
private String denumire;
protected String descriere;
private Long durataEstimata = 0l;
private Date dataEstimata = new Date();
// restrict setDataFinalizare to be generated
@Setter(AccessLevel.NONE)
private Date dataFinalizare;
}

15
Încapsularea METODELOR -
Încapsulare comportamentală
❏ “Ascunderea” metodelor, facându-le inaccesibile din
exterior, constituie esenţa principiului încapsulării
comportamentale care afirmă că numai operaţiile
necesare (relevante) a fi invocate din exterior să fie
accesibile.
❏ Algoritmul de implementare a metodelor accesibile
(publice) poate fi modularizat cu ajutorul metodelor
interne (declarate private) inaccesibile din exterior.

16
Exemplu încapsulare atribute și metode::
org.encapsulation.members

❏ Clasa TestIncapsulareAtribute [utilizare/invocare


operații proprietăți].
❏ Clasa JavaBean inițială Cerinta
❏ get/set durataEstimata, dataEstimata
❏ get get dataFinalizare
❏ Clasele: CerintaData (lombok) și CerintaRecord
❏ Clasa TestIncapsulareOperatii [utilizare/invocare
operații publice].
❏ Clasa Sprint
❏ accesibilitate public-ă
❏ getDataFinalizare()
❏ Modularizare internă private
❏ getDurataEstimataSprint()

17
Încapsularea sau împachetarea CLASELOR
● Clasele pot fi declarate:
○ (direct) în interiorul pachetelor:
■ pot fi publice, accesibile din exteriorul pachetelor;
■ pot fi neînsoţite de specificatorul de vizibilitate public:
accesibilitatea fiind limitată doar membrilor pachetului (doar
la clasele declarate în interiorul pachetului).
○ în interiorul altor clase: în acest fel se creează clase
interne (nested/inner classes), care pot fi:
■ de tip:
● clase interne statice;
● clase interne non-statice.
■ accesibile prin specificatori:
● public;
● privat;
● protected.
18
Clase abstracte, interne, anonime

19
Exemplu încapsulare clase ::
[org.encapsulation.classes.*]

● Domain Model
○ Cerinta - Task - DetaliuTask
● Pachete
○ org.encapsulation.classes ::
■ clasa Cerinta
■ import org.encapsulation.classes.domain.Task
○ org.encapsulation.classes.domain ::
■ clasa Task, enums StatusTask, CategorieTask
■ Clasa internă: Task.DetaliuTask
● Clasa Test org.encapsulation.classes.TestIncapsulareClase
○ Invocare clase încapsulate

20
Încapsularea pachetelor și serviciilor
prin intermediul modulelor (Java 9)
● Un modul -> un fișier-arhivă .jar
○ Dependent de alte module din alte fișiere .jar din
classpath
● root-module-dir\module-info.java
○ module <module-name>{
■ requires transitive <other-module>
■ opens <package> to <other-module>
■ exports <package> to <other-module>

■ uses <service-definition-class-or-definition>
■ provides <service-definition-class-or-definition>
● with <service-implementation-class-or-definition>
○ }
Java Modularity, JIGSAW, Examples
21
1.2 Principiul abstractizării prin interfeţe
● Interfaţa reprezintă un mecanism de extragere,
separare sau abstractizare a definiţiei tipului faţă de
implementare.
○ Interfeţele (ca și clasele abstracte) nu permit instanţierea
directă.
○ Interfețele sunt implementate concret prin clase cu
implementări conforme specificațiilor abstracte.
● Tipizarea reprezintă (re)cunoașterea obiectelor prin
tipurile-interfețelor implementate.

* 22
Sub-tipizare şi interfeţe
● Definiţia interfețelor se limitează doar la
membri-operaţii, nu permit declarare de variabile de
instanţă (evitarea detaliilor de implementare):
○ pot fi adăugate constante-statice pentru declararea
valorilor “legale” ce formează domeniul discret al
unor eventuali parametri sau atribute și proprietăți;
○ pot fi adăugate operații cu metode de implementare
default.
○ pot fi adăugate operații static-e cu metode de
implementare.
Ex. domeniu STARE:
static final Integer NOUA = 1;
static final Integer IN_PROGRES = 2;
static final Integer COMPLETA = 3;
static final Integer INCHISA = 4;
void setStare(Integer stareModificata);
* 23
Implementarea interfeţelor

● O clasă implementează o interfaţă în mare parte


la fel cum o clasă abstractă este extinsă -
extends - de subclasele sale concrete.
○ Faptul că o clasă se conformează unei interfeţe
trebuie declarat în mod explicit prin intermediul
cuvântului cheie implements.

● O clasă poate implementa mai multe interfețe,


prin urmare instanțele unei clase pot fi conforme
mai multor interfețe.

* 24
Interfețe și polimorfism

● Interfețele pot fi folosite polimorfic în următoarele moduri:


○ (1) Pentru abstractizarea comportamentelor (serviciilor).
○ (2) Pentru abstractizarea tipurilor de date (TADs):
■ componentele (proprietățile) sunt definite prin
operații-accessori (getteri și setteri);
■ TAD pot avea mai multe forme de materializare prin
mai multe clase concrete de implementare.

25
Tipuri abstracte de date TAD în Java

❏ Tipul abstract de date este un principiu operabil în


limbajul Java datorită faptului că:
❏ operaționalizarea structurii de date a obiectelor se poate
realiza prin protejarea accesului membrilor variabile de
instanță folosind convenția get/set a standardului
JavaBeans;
❏ abstractizarea componentelor operaționalizate get/set se
poate formaliza folosind conceptul de interfață.

26
Tipuri abstracte de date TAD în Java

Principii definitorii modelului Reprezentare Java


TAD

Componente/Reprezentare Reprezentare externă: prin proprietăți


<public>e (încapsulare atribute interne)
Abstractizarea reprezentării externe
(accessori-proprietăți) printr-o interfață.
Reprezentare internă: prin atribute sau
variabile de instanță <private>,

Operațiuni/manipulare Definire comportament prin membri


operații <public>e

Integritate Restricţii de stare incluse în metodele de


implementare ale operațiilor get/set.

27
Exemplu: TAD-UML cu proprietăţi JavaBean

ex. 2.4
28
Exemplu interfață-TAD :: org.abstracting.interfaces

❏ Interfața IProiect [declarare TAD - def. proprietăți]


❏ Interfața IPrintable [abstractizare comportamentală]
❏ Clasa Proiect [implementare proprietăți]
❏ private
❏ nrProiect, numeProiect, dataStart;
❏ public
❏ getNrProiect(), getNumeProiect(), getDataStart()
❏ getReleaseCount()
❏ Clasa TestInterfaceTAD
❏ utilizare/invocare proprietăți,
❏ invocare comportament

29
2. Principiul reutilizabilității obiectelor
● Principiul reutilizabilității obiectelor se referă la faptul
că scopul creării obiectelor constă în invocarea
funcţionalităţii asociate acestora: de fiecare dată
când un obiect este instanţiat, funcţionalitatea
declarată/definită a acestuia urmează a fi
(re)utilizată.
● Reutilizarea claselor este ingredientul fundamental în
construirea unor noi structuri:
○ prin compunere (reutilizare prin referenţiere structurală),
○ prin derivare (reutilizare prin moştenire).

30
2.1 Reutilizabilitate prin Compunere
● Plasarea de referinţe ale unor obiecte în structura noilor
clase are drept consecințe:
○ (d.p.d.v) semantic: obiectele compuse vor include
structural obiectele componente;
○ (d.p.d.v) al implementării: obiectele compuse conţin
câmpuri ce stochează referinţe către obiectele
componente.
● Diferența (semantică) compunere vs. agregare:
○ compunere: dependenţă puternică => componente
“captive”;
○ agregare: dependenţă slabă => componente partajabile.

31
Exemplu: Modelare UML Compunere

32
Exemplu compunere ::
[org.reusability.classes]
public class Sprint {
private List<Cerinta> cerinte = new ArrayList<>();
}

public class Cerinta {


private List<Task> taskuri = new ArrayList<>();
}

public class Task{

33
2.2 Reutilizabilitate prin moștenire
Specializarea și Generalizarea claselor
● Extinderea setului de caracteristici ale unei clase de
bază prin includerea unor caracteristici specifice =
adăugarea diferenţelor =>
○ Clase diferenţiate pornind de la o bază comună
– SPECIALIZARE.

● Abstractizare = eliminarea diferenţelor =>


○ Sintetizarea unei (super)clase ce cumulează
caracteristicile comune ale (sub)claselor inițiale
– GENERALIZARE.

34
Exemplu: Modelare UML Specializare

35
Reutilizabilitate prin clase abstracte
● Clasele declarate abstracte nu pot fi instanţiate în
mod direct.
● Instanţe ale acestor clase se obţin prin intermediul
claselor concrete care le moştenesc.
● Metodele abstracte sunt specificate în clasele
abstracte şi sunt implementate în clasele concrete.
● Clasele abstracte pot apare:
○ ca efect al specializării: toate instanțele clasei generice
pot fi obținute prin instanțierea claselor concrete
○ ca efect al generalizării: cumularea caracteristicilor
comune, reutilizabile în clase abstracte pentru
simplificarea structurii claselor concrete.

36
Exemplu specializare ::
[org.reusability.classes]
public abstract class Cerinta {

public class CerintaFunctionala extends Cerinta {

public class CerintaTehnica extends Cerinta {

37
Exemplu clasa abstracta: Specializare
[org.reusability.classes]

❏ Clasa abstracta Cerinta


❏ Clase concrete
❏ CerintaFunctionala,
❏ CerintaTehnica
❏ Test
❏ TestCompunereSpecializare

38
Moștenire în structura obiectelor
● Prin specializare în subclase, obiectele subclaselor
moştenesc atributele (variabilele de instanţă) care
formează scheletul structural al claselor părinte.
● Accesul din contextul sub-claselor la variabilele de
instanţă care provin din super-clase este dependent
de specificatorii de vizibilitate:
○ (package), protected, public.

● Mecanismul de iniţializare a instanţelor din subclase


trebuie să permită şi iniţializarea variabilelor de
instanţă moştenite, eventual, chiar la nivelul
superclaselor, fapt marcat prin invocarea
super-constructorilor (constructorii super-claselor):
○ super()
* 39
Supra-scriere şi supra-încărcare structurală
● Subclasele nu pot redefini atributele de la nivelul
super-claselor (chiar dacă pot fi accesate).
● În sub-clase (numele) atributelor din super-clase
pot fi (însă) supra-încărcate cu atribute proprii:
○ pot fi definite atribute în sub-clase cu nume ce se
regăsesc definite şi la nivelul super-claselor;
○ diferenţierea între atributele supra-încărcate se poate
face prin referenţierea acestora raportat la sub-clasă
sau super-clasă prin cuvintele cheie super şi this.

40
Exemplu moștenire atribute:
[org.reusability.inheritance.attributes]
● Clase: Cerinta, CerintaFunctionala
○ atribute: categorie, descriere, descriereUseCase
● Exemplu supraîncărcare nume atribute si invocare
constructori: this vs.super:
TestOverloadingAttributes

41
Moştenire comportamentală
● Prin specializare în subclase, obiectele subclasate
moştenesc operaţiile şi metodele de implementare
care formează comportamentul claselor părinte.
● Accesul din contextul sub-claselor la operaţiile care
provin din super-clase este dependent de specificatorii
de vizibilitate:
○ private, (package), protected, public.

● Prin moştenire: obiectele din sub-clase au aceleaşi


carateristici şi se comportă similar cu cele din
super-clase:
○ pentru ca relaţia de generalizare superclasă – subclasă să
fie semantic corectă, aserţiunea <o instanţă sub-clasă>
[este gen sau fel de/is a kind of] <o instanţă super-clasă>
trebuie să fie veridică.
42
Supra-scriere şi supra-încărcare operații
Overriding & Overloading
● La nivelul unei sub-clase:
○ o metodă moştenită poate fi redefinită (suprascrisă), adică
implementarea unei operaţii poate fi schimbată în
subclase;
○ poate fi definită o operaţiune cu acelaşi nume dar mod de
parametrizare diferit (supraîncărcare): ca urmare
instanţele sub-clasei pot fi invocate prin acelaşi nume de
operaţie dar care, funcţie de numărul şi tipul argumentelor,
vor fi mapate pe implementări comportamentale distincte.

● La nivelul super-claselor definite ca abstracte pot fi


definite anumite operaţii fără implementările aferente
(operaţii abstracte), sub-clasele concrete având
sarcina asocierii unei implementări corespunzătoare.

43
Constructori în ierarhii de moștenire
❏ Constructorul reprezintă o metodă asociată oricărei
clase şi care este apelată în momentul creării
instanţelor. Numele constructorului desemnează o
metodă-membru cu numele clasei, şi nu prezintă un tip
returnat (nici măcar void).
❏ Constructorii sunt metode care nu se moștenesc: nu
sunt metode specifice instanțelor, nu pot fi apelate la
nivelul obiectelor instanțiate.
❏ Fiecare subclasă va invoca implicit sau explicit, din
cadrul propriilor constructori, un constructor al clasei
părinte prin sintaxa super() cu sau fără argumente.

44
Tipuri de constructori
❏ Tipuri:
❏ Constructorul default (adăugat de compilator în lipsa unui
constructor explicit).
❏ Constructorul fără parametri, this().
❏ Constructorul parametrizat, this(args).
❏ Regula supraîncărcării constructorilor: toţi constructorii
au acelaşi “nume” care corespunde cu numele clasei.
❏ Prima instrucțiune din cadrul unui constructor
❏ va invoca constructorul clasei părinte super(args)
❏ sau va invoca un alt constructor local this(args) care va
apela constructorul clasei părinte.
❏ Dacă această instrucțiune nu este explicită, compilatorul
va adăuga/genera implicit super().

45
Diferenţierea metodelor supraîncărcate
● Numele metodelor pot fi supraîncărcate prin
impunerea restricţiei ca fiecare să aibă o listă de
argumente unică prin:
○ numărul argumentelor;
○ tipul argumentelor;
○ ordinea argumentelor.
● Nu se iau în considerare numele argumentelor şi
nici tipul returnat.

46
Moştenire multiplă şi interfeţe
● O deosebirea esenţială dintre interfeţe şi ierarhiile de
clase rezidă în faptul că, în cazul primelor, acestea pot
extinde mai mult decât un singur părinte.
● O clasă în sine poate implementa în mod direct mai
multe interfeţe. Adică ar putea avea mai mulţi
“părinţi”-interfeţe, în afară, eventual, de unul singur care
ar putea fi o clasă obişnuită.
○ Regulile de subtipizare care se aplică claselor se aplică
în aceeași măsură şi interfeţelor.

47
Restricționarea ierarhiei de moștenire

● Clasele declarate final


○ Nu permit extinderea lor prin subclase (ierarhie
complet închisă).
● Clasele declarate sealed
○ permit doar anumitor sub-clase să extindă ierarhia de
moștenire.
○ Într-o ierarhie “închisă/sealed” anumite sub-clase pot fi
lăsate deschise declarându-le non-sealed.
● Interfețele declarate sealed
○ la fel ca și în cazul claselor, pot restricționa ierarhiile de
moștenire prin extindere (extends) sau implementare
(implements).

48
Exemplu ierarhie de moștenire

interface Angajat

sealed class Membru implements Angajat


permits LiderEchipa, ManagerProiect

non-sealed class ManagerProiect


extends Membru
final class LiderEchipa extends Membru

class ProductManager
extends ManagerProiect

49
Exemplu moștenire operații :
[org.reusability.inheritance.operations]
● Ierarhie Membru (refactoring … Persoana)
○ prop. rol;
○ prop. ManagerProiect :: competente;
■ overloading: getCompetente()
○ constructori subclase ManagerProiect, LiderEchipa;
○ ierarhie sealed - clasa Membru;
○ overriding în subclasa ManagerProiect:setRole()
● Ierarhie Cerinta:
○ proprietate categorie, protected;
■ overriding: setCategorie()
○ constructori în subclase;
○ ierarhie deschisă: clasa Cerinta declarată abstractă;
● TestOverridingOverloadingOperations

50
2.3 Object Oriented Design Patterns

● Design Pattern Concept


● Design Pattern Types
● Representative OO Design Patterns

51
Design Patterns

● “The design patterns […] are descriptions of


communicating objects and classes that are
customized to solve a general design problem in a
particular context.” (Gamma et al.,, 1995)
● “The purpose of a pattern is to provide general advice
or structure to guide your design.” (Burns, 2018)
● “The focus of the pattern is a particular solution, one
that’s both common and effective in dealing with one
or more recurring problems.” (Fowler, 2003)

52
Design Pattern Types

● Generic (Go4) OO Patterns:


○ Creational: Builder, Factory, Singleton
○ Behavioral: Command, Iterator, Observer, State
○ Structural: Adapter, Composite, Facade.
● Architectural Patterns:
○ Layered Architecture
○ Application Service
○ Business Object
○ Application Controller.
● Integration Application Patterns
○ Document Message
○ Message Router
○ Messaging Gateway.
53
Factory Method Pattern

● Problema: delegarea (și amânarea) instanțierii unor


(sub)clase.
● Strategia: Crearea unei clase complementare (helper)
care să permită instanțierea (sub)claselor inițiale
printr-o metodă(funcție) statică.
● Un Builder ar putea fi considerat o strategie specifică
de Factory.

54
Implementare Factory

● Abordarea directă
○ implementare completă a clasei Factory
■ org.design.patterns.factory.CerintaFactory
● Exemple Java Standard Library
○ java.time.LocalDate.now()
○ java.time.LocalDate.of()
○ Double.valueOf()
○ java.util.Calendar.getInstance()
○ java.util.List.of()

55
Builder Pattern

● Problema: separarea definirii unui obiect complex față de


reprezentarea acestuia.
● Strategia: segmentarea procesului de creare într-o serie
de pași (înlănțuiți) aflați în responsabilitatea unei clase
distincte utilitare.
● Implementare Java (Builder pentru Bean):
○Crearea unei clase distincte complementare (de regulă internă și
statică clasei Bean).
○ Specificarea unui constructor în Builder cu parametri minimali pentru
instanța Bean (sau doar a constructorului default, fără parametri).
○ Specificarea mai multor metode înlănțuite (care returnează referința
Builder) pentru celelalte componente ale instanței Bean.
○ Furnizarea unei metode de finalizare a procesului build() care să
returneze instanța Bean completă.
56
Implementare Builder

● Abordarea directă:
○ implementare completă a clasei Builder
■ org.design.patterns.builder.Cerinta.CerintaBuilder
● Abordarea declarativă lombok @Builder, @With
● Exemple Builder în Java Standard Library:
○ java.util.Calendar.Builder.set…().build();
○ java.time.LocalDate.now().with…();
○ new StringBuilder().append().append().toString().

57
Singleton Pattern

● Problema: restricționarea instanțierii unice a unei clase


cu asigurarea unui punct de access la instanța unică.
● Strategia: imposibilitatea apelării directe a
constructorului din clasa țintă și implementarea
punctului de access printr-o metodă statică.
● Implementare Java:
○ Construire clasă țintă cu un constructor declarat private.
○ Stocare internă (private) într-un câmp static final private
inițializat prin apelul constructorului privat.
○ Creare metodă statică getInstance() care să returneze
referința din câmpul intern privat.

58
Implementare Singleton

● Abordarea directă
○ implementare completă a clasei Singleton
■ org.design.patterns.singleton.ComputeCerintaService
■ org.design.patterns.singleton.ComputeCerintaStaticService
● Abordare declarativă
○ Adnotarea @Singleton în aplicații Java/Jakarta Enterprise
(SessionBean components).
○ Adnotarea @Bean@Scope(“singleton”) în aplicații cu
Spring Framework (Spring DI components).
● Exemple Java Library
○ java.util.Calendar.getInstance()

59
Exemple design patterns :
[org.design.patterns]
● org.design.patterns.factory.CerintaFactory
○ Metode factory:
■ getCerinta() pentru ierarhia ICerinta
■ getInstace() doar pentru clasa Cerinta
● org.design.patterns.builder
○ Clasa Bean: Cerinta
○ Clasa Builder: Cerinta.CerintaBuilder
● org.design.patterns.singleton
○ Clasa cu instanță Singleton: ComputeCerintaService
○ Clasa statică: ComputeCerintaStaticService
● org.design.patterns.factory.TestFactory
● org.design.patterns.builder.TestBuilder
● org.design.patterns.singleton.TestSingleton
60
References. Tutorials. Links
● Encapsulation
○ TutorialsPoints: Encapsulation
○ JavaCodeGeeks: Encapsulation
○ Learneroo:
● Composition
○ JavaCodeGeeks: Inheritance&Composition
● Subclasses and inheritance
○ TutorialsPoints: Inheritance
○ Oracle JavaSE Tutorials: Inheritance concept
○ JavaCodeGeeks: Inheritance
○ Learneroo: Inheritance
● Design patterns
○ https://www.digitalocean.com/community/tutorials/builde
r-design-pattern-in-java
61
Java Books References
Ivor Horton, Beginning Java®, Java 7 Edition, John Wiley &
Sons, Inc, 2011, ISBN: 978-0-470-40414-0
Kishori Sharan, Beginning Java Language Features: With
Modules, Streams, Threads, I/O, and Lambda Expressions,
2nd Ed., Apress, 2018
Kishori Sharan, Beginning Java 9 Fundamentals: Language
Syntax, Arrays, Objects, Modules, JShell and Regular
Expressions, 2nd Edition, Apress, 2017

62
Java Books References
● Erich Gamma, Richard Helm, Ralph Johnson, John
Vlissides, Design Patterns: element of reusable
object-oriented software, Addison-Wesley, 1995
● [Burns, 2018] Brendan Burns, Designing Distributed
Systems. Patterns and Paradigms for Scalable, Reliable
Services, O’Reilly Media, Inc., 2018
● [Fowler et a., 2002] Martin Fowler, David Rice,
Matthew Foemmel, Edward Hieatt, Robert Mee, Randy
Stafford, Patterns of Enterprise Application
Architecture, Addison Wesley, 2002

63

S-ar putea să vă placă și