Ací es mostren les diferències entre la revisió seleccionada i la versió actual de la pàgina.
|
patrons_disseny [2022/11/24 07:47] albert_palacios_jimenez creat |
patrons_disseny [2022/11/24 08:20] (actual) albert_palacios_jimenez |
||
|---|---|---|---|
| Línia 6: | Línia 6: | ||
| ---- | ---- | ||
| - | ==== Exemples | + | ==== Patrons de disseny |
| + | |||
| + | - Fa referència a solucions de programació usades habitualment al dissenyar software. | ||
| + | |||
| + | - Habitualment els patrons de disseny es consideren bones pràctiques a la hora de programar. | ||
| + | |||
| + | - A vegades es critica alguns patrons de disseny ja que poden ser resultat d’un mal disseny del software, en aquests casos s’anomenen ‘anti-patrons’ | ||
| + | |||
| + | ==== Paradigmes de programació ==== | ||
| + | |||
| + | Els diferents llenguatges de programació ofereixen diferents eines per solucionar els problemes que surten a la hora de dissenyar el software. En la programació imperativa hi ha dos paradigmes: | ||
| + | |||
| + | - **Programació procedural**, | ||
| + | |||
| + | <code c> | ||
| + | struct persona0 { | ||
| + | String nom; | ||
| + | String edat; | ||
| + | } | ||
| + | |||
| + | function aniversari () { | ||
| + | persona0.edat += 1; | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | - **Programació orientada en objectes**, en què les instruccions formen part de l’estat de l’objecte en què es declaren | ||
| + | |||
| + | <code java> | ||
| + | public class Persona { | ||
| + | String nom; | ||
| + | String edat; | ||
| + | public void aniversari () { | ||
| + | edat += 1; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Orientació a objectes ==== | ||
| + | |||
| + | És un paradigma en què la programació es fa definint objectes, que contenen dades i codi. | ||
| + | |||
| + | - **Dades**, o propietats de l’objecte | ||
| + | |||
| + | - **Codi**, procediments que operen sobre les dades (funcions) | ||
| + | |||
| + | |||
| + | Cal distingir entre les definicions i els objectes funcionals | ||
| + | |||
| + | - **Classes**, | ||
| + | |||
| + | <code java> | ||
| + | public class Poligon { | ||
| + | int num_vertex = 1; | ||
| + | String nom = “linia” | ||
| + | public Poligon (v1, n1) { | ||
| + | num_vertex = v1; | ||
| + | nom = n1; } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | - **Instàncies**, | ||
| + | |||
| + | <code java> | ||
| + | public static void Main (String[] args) { | ||
| + | Poligon pL = new Poligon(2, “linia”); | ||
| + | Poligon pT = new Poligon(3, “triangle”); | ||
| + | Poligon pQ = new Poligon(4, “quadrat”); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | pL, pT i pQ són instàncies de la classe Poligon | ||
| + | |||
| + | == Java, extends == | ||
| + | |||
| + | Quan volem fer servir les propietats i mètodes d’una classe pare fem servir ‘**extends**’. | ||
| + | |||
| + | També podem sobre-escriure els mètodes de la classe filla amb ‘**@Override**' | ||
| + | |||
| + | <code java> | ||
| + | package SuperClass; | ||
| + | public class SuperClass { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package SuperClass; | ||
| + | public class SubClass extends SuperClass { | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package SuperClass; | ||
| + | public class Main { | ||
| + | | ||
| + | | ||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == Java, implements == | ||
| + | |||
| + | Una clase abstracta que agrupa mètodes buits, que s’han d’implementar en altres classes | ||
| + | |||
| + | |||
| + | <code java> | ||
| + | package Animals; | ||
| + | interface Animal { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | |||
| + | package Animals; | ||
| + | class Anec implements Animal { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package Animals; | ||
| + | class Gos implements Animal { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package Animals; | ||
| + | public class Main { | ||
| + | | ||
| + | Anec a = new Anec(); | ||
| + | Gos g = new Gos(); | ||
| + | |||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == Java, mètodes abstractes == | ||
| + | |||
| + | Les classes abstractes es declaren sense implementació, | ||
| + | |||
| + | <code java> | ||
| + | package Animals2; | ||
| + | abstract class Animal { | ||
| + | | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package Animals2; | ||
| + | class Anec extends Animal { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package Animals2; | ||
| + | class Gos extends Animal { | ||
| + | | ||
| + | | ||
| + | } | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | |||
| + | package Animals2; | ||
| + | public class Main { | ||
| + | | ||
| + | Anec a = new Anec(); | ||
| + | Gos g = new Gos(); | ||
| + | | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | ==== Prototype ==== | ||
| + | |||
| + | Prototype és un patró que ens permet crear còpies d’objectes sense que dependre de les seves classes. | ||
| + | |||
| + | Quan volem una còpia exacte d’un objecte tenim algun problema: | ||
| + | |||
| + | - Els objectes poden tenir mètodes privats que no podem veure | ||
| + | |||
| + | - Com que cal conèixer la classe original, pot ser que implementi una altre classe | ||
| + | |||
| + | El patró “prototype” delega el procés de clonar un objecte als propis objectes que estan essent clonats. | ||
| + | |||
| + | Per fer-ho, es crea una “interficie” amb almenys el mètode “clone” que crea un objecte de la classe actual amb tots els valors de l’objecte antic | ||
| + | |||
| + | Quan es fa servir Prototype? | ||
| + | |||
| + | - Quan el teu codi no hagi de dependre de les classes que necessites copiar | ||
| + | |||
| + | - Imagina que tens una clase complexa que és complicada de configurar, prototype permet tenir diferents objectes configurats llestos per clonar i usar | ||
| + | |||
| + | Amb prototype hem de crear el mètode ' | ||
| + | <code java> | ||
| + | import java.util.Objects; | ||
| + | |||
| + | public abstract class Poligon { | ||
| + | |||
| + | public int x; | ||
| + | public int y; | ||
| + | public String color; | ||
| + | |||
| + | public Poligon() {} | ||
| + | |||
| + | public Poligon(Poligon target) { | ||
| + | if (target != null) { | ||
| + | this.x = target.x; | ||
| + | this.y = target.y; | ||
| + | this.color = target.color; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public abstract Poligon clone(); | ||
| + | |||
| + | @Override | ||
| + | public boolean equals(Object object2) { | ||
| + | if (!(object2 instanceof Poligon)) return false; | ||
| + | Poligon cast2 = (Poligon) object2; | ||
| + | return cast2.x == x && cast2.y == y && cast2.color.equals(color); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | <code java> | ||
| + | public class Cercle extends Poligon { | ||
| + | |||
| + | public int radius; | ||
| + | |||
| + | public Cercle() { | ||
| + | } | ||
| + | |||
| + | public Cercle(Cercle target) { | ||
| + | super(target); | ||
| + | if (target != null) { | ||
| + | this.radius = target.radius; | ||
| + | } | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public Poligon clone() { | ||
| + | return new Cercle(this); | ||
| + | } | ||
| + | |||
| + | @Override | ||
| + | public boolean equals(Object object2) { | ||
| + | if (!(object2 instanceof Poligon) || !super.equals(object2)) return false; | ||
| + | Cercle cast2 = (Cercle) object2; | ||
| + | return cast2.radius == radius; | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == Exemple de Prototype == | ||
| + | |||
| + | {{ :: | ||
| + | |||
| + | ==== Factory ==== | ||
| + | |||
| + | Substituir la creació d’objectes a través de ‘new’ per crides a metodes ‘factory’ específics de cada classe. | ||
| + | |||
| + | Els objectes es segueixen creant amb ‘new’, però es fa de manera interna al mètode ‘factory’ | ||
| + | |||
| + | El objectes creats a través de ‘factory’ s’anomenen ‘products’ | ||
| + | |||
| + | Quina és la motivació de Factory? | ||
| + | |||
| + | - Els clients d’una llibreria no tenen que saber com funciona aquesta llibreria, o fins i tot el tipus d’objecte o constructors que es fan servir. | ||
| + | |||
| + | - Amb factory tens un ‘product’ que declara una interfície comú a tots els objectes i les seves subclasses | ||
| + | |||
| + | - Cal que hi hagi una classe ‘creator’ que té el mètode per fabricar ‘products’ | ||
| + | |||
| + | Quan es fa servir factory? | ||
| + | |||
| + | - Quan no sabem amb quins tipus d’objectes i dependencies haurà de treballar el nostre codi | ||
| + | |||
| + | - Quan volem donar maneres d’extendre els components de la nostre llibreria | ||
| + | |||
| + | - Quan volem estalviar recursos del sistema, aprofitant objectes enlloc de refentlos cada vegada | ||
| + | |||
| + | En Java Factory es pot implementar a través de: | ||
| + | |||
| + | - interface i classes que implementen les seves funcions | ||
| + | |||
| + | - amb classes derivades (extends) i sobreescrivint les funcions necessàries | ||
| + | |||
| + | Transportation.java | ||
| + | <code java> | ||
| + | public interface Transportation { | ||
| + | void deliverPackage(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | FactoryTransportation.java | ||
| + | <code java> | ||
| + | public class FactoryTransportation { | ||
| + | |||
| + | public static Transportation getTransportation(String method) { | ||
| + | |||
| + | if(" | ||
| + | return new TransportationShip(); | ||
| + | else if(" | ||
| + | return new TransportationTruck(); | ||
| + | else if(" | ||
| + | return new TransportationVan(); | ||
| + | |||
| + | return null; | ||
| + | } | ||
| + | |||
| + | public static void deliver (Transportation transport) { | ||
| + | transport.deliverPackage(); | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | TransportationShip.java | ||
| + | <code java> | ||
| + | public class TransportationShip implements Transportation { | ||
| + | |||
| + | @Override | ||
| + | public void deliverPackage() { | ||
| + | System.out.println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | TransportationTruck.java | ||
| + | <code java> | ||
| + | public class TransportationTruck implements Transportation { | ||
| + | |||
| + | @Override | ||
| + | public void deliverPackage() { | ||
| + | System.out.println(" | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | == Exemple de Factory == | ||
| + | |||
| + | {{ :: | ||
| + | |||
| + | ==== Singleton ==== | ||
| + | |||
| + | Singleton assegura que només hi ha una instància d’una classe determinada | ||
| + | |||
| + | Crees un objecte, si al cap d’una estona tones a crear un objecte d’aquella classe reps l' | ||
| + | |||
| + | Permet accedir un objecte de manera global en un programa, protegint-lo de sobre-escriptures | ||
| + | |||
| + | Com es fa? | ||
| + | |||
| + | - Posar el constructor de la classe com a ‘private’ | ||
| + | |||
| + | - Fer un mètode de creació ‘static’ que funciona com a constructor, | ||
| + | |||
| + | * El primer cop crida al constructor privat | ||
| + | * | ||
| + | * La resta de vegades, retorna l’objecte creat originalment | ||
| + | |||
| + | Avantages: | ||
| + | |||
| + | - Assegura que només hi ha una instància de la classe | ||
| + | |||
| + | - Es pot accedir a l’objecte de manera global | ||
| + | |||
| + | - Només s’inicia el primer cop | ||
| + | |||
| + | Crítiques: | ||
| + | |||
| + | - Es considera un ‘anti-patró’ que pot amagar un mal disseny de l’aplicació | ||
| + | |||
| + | - En entorns amb threads cal assegurar que diversos fils no creen un objecte ‘singelton’ diverses vegades | ||
| + | |||
| + | Exemple de Singleton: | ||
| + | |||
| + | <code java> | ||
| + | public final class ExempleSingleton { | ||
| + | |||
| + | | ||
| + | | ||
| + | |||
| + | | ||
| + | | ||
| + | } | ||
| + | |||
| + | | ||
| + | if (instance == null) { | ||
| + | | ||
| + | } | ||
| + | | ||
| + | } | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Els Singletons també es poden ' | ||
| + | |||
| + | <code java> | ||
| + | ExempleSingleton instanceOne = ExempleSingleton.getInstance(" | ||
| + | ExempleSingleton instanceTwo = null; | ||
| + | try { | ||
| + | Constructor[] constructors = ExempleSingleton.class.getDeclaredConstructors(); | ||
| + | for (Constructor constructor : constructors) { | ||
| + | //Below code will destroy the singleton pattern | ||
| + | constructor.setAccessible(true); | ||
| + | instanceTwo = (ExempleSingleton) constructor.newInstance(" | ||
| + | break; | ||
| + | } | ||
| + | } catch (Exception e) { e.printStackTrace(); | ||
| + | </ | ||
| + | |||
| + | Què passa amb els objectes serialitzables? | ||
| + | |||
| + | Tot i que hi ha maneres d’implementar Singleton en objectes serialitzables, | ||
| + | |||
| + | == Exemple de Singleton == | ||
| + | |||
| + | {{ :: | ||
| + | |||
| + | ==== DAO, Data Access Object ==== | ||
| + | |||
| + | DAO es fa servir per separar la manera de guardar les dades i la l’estructura lògica amb la que s’hi treballa a nivell de programació. | ||
| + | |||
| + | Una interfície base DAO defineix les funcions que implementen tots els objectes DAO | ||
| + | |||
| + | Cada objecte DAO implementa la transformació entre la seva Classe i on estan emmagatzemades les dades | ||
| + | |||
| + | Una manera habitual de definir quines funcions ha de implementar DAO és CRUD, que significa: | ||
| + | |||
| + | - Create | ||
| + | |||
| + | - Read | ||
| + | |||
| + | - Update | ||
| + | |||
| + | - Delete | ||
| + | |||
| + | I són les operacions més habituals al treballar amb models de dades | ||
| + | |||
| + | <code java> | ||
| + | public interface Dao< | ||
| + | |||
| + | void add(T t); // Equival a Create | ||
| + | |||
| + | T get(int id); // Equival a Read | ||
| + | | ||
| + | |||
| + | void update(int id, T t); | ||
| + | |||
| + | void delete(int id); | ||
| + | |||
| + | void print(); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Avantatges de DAO | ||
| + | |||
| + | - Simplifica el treball dels programadors al abstreure l’estructura de dades de l’arquitectura del programa | ||
| + | |||
| + | - Unifica la manera de fer les crides pels diferents tipus d’objectes independentment de com es guarden les seves dades | ||
| + | |||
| + | Inconvenients: | ||
| + | |||
| + | - A vegades es defineixen massa funcions DAO fent que sigui difícil de mantenir o impossible d’aplicar a totes les dades per igual | ||
| + | |||
| + | - Resta flexibilitat, | ||
| + | |||
| + | - Separar la lògica de les dades pot implicar necessitar operacions “extra” per guardar les modificacions del model de dades | ||
| + | |||
| + | == Exemple de DAO == | ||
| + | |||
| + | {{ :: | ||
| + | |||
| + | ==== Observer ==== | ||
| + | |||
| + | Es crida a un mètode quan una variable cambia de valor. | ||
| + | |||
| + | Tradicionalment un objecte, manté una llista d’observadors que criden a mètodes quan hi ha canvis a l’estat de l’objecte (valors de les variables). | ||
| + | |||
| + | No hi ha una manera específica d’implementar l’observer, | ||
| + | |||
| + | Usos més habituals d' | ||
| + | |||
| + | - En interfícies gràfiques quan un usuari canvia un ‘input’ (text, select, checkbox, …) per executar funcions que s' | ||
| + | |||
| + | - Quan les dades canvien remotament i rebem els nous valors, aquests han d’actualitzar la interfície gràfica automàticament. O executar processos que tractin aquestes noves dades rebudes adeqüadament. | ||
| + | |||
| + | - Quan s’observa una carpeta d’arxius o un arxius i si hi ha canvis s’executa una acció (normalment ho fa un ‘thread’ paral·lel al procés) | ||
| + | |||
| + | En java cal definir l' | ||
| + | |||
| + | <code java> | ||
| + | Observable< | ||
| + | @Override | ||
| + | public void propertyChange(Integer oldValue, Integer newValue) { | ||
| + | System.out.printf(" | ||
| + | } | ||
| + | }; | ||
| + | </ | ||
| + | |||
| + | Observable.java | ||
| + | <code java> | ||
| + | public abstract class Observable< | ||
| + | |||
| + | private T value; | ||
| + | |||
| + | public Observable(T value) { | ||
| + | this.value = value; | ||
| + | } | ||
| + | |||
| + | public T getValue() { | ||
| + | return value; | ||
| + | } | ||
| + | |||
| + | public void setValue(T value) { | ||
| + | T oldValue = this.value; | ||
| + | this.value = value; | ||
| + | this.propertyChange(oldValue, | ||
| + | } | ||
| + | |||
| + | public abstract void propertyChange(T oldValue, T newValue); | ||
| + | } | ||
| + | </ | ||
| + | |||
| + | Cada classe que vol observar alguna propietat necessita una llista d' | ||
| + | |||
| + | <code java> | ||
| + | import java.beans.PropertyChangeListener; | ||
| + | import java.beans.PropertyChangeSupport; | ||
| + | |||
| + | public class CotxeEvents { | ||
| + | private PropertyChangeSupport llistaObservers = new PropertyChangeSupport(this); | ||
| + | |||
| + | private CotxeEstats estat; | ||
| + | private int gasolina; | ||
| + | |||
| + | CotxeEvents () { | ||
| + | this.estat = CotxeEstats.ATURAT; | ||
| + | this.gasolina = 3; | ||
| + | } | ||
| + | |||
| + | public void addPropertyChangeListener(String name, PropertyChangeListener listener) { | ||
| + | llistaObservers.addPropertyChangeListener(name, | ||
| + | } | ||
| + | |||
| + | public void removePropertyChangeListener(String name, PropertyChangeListener listener) { | ||
| + | llistaObservers.removePropertyChangeListener(name, | ||
| + | } | ||
| + | |||
| + | public void setEstat (CotxeEstats newValue) { | ||
| + | CotxeEstats oldValue = this.estat; | ||
| + | if (oldValue != newValue) { | ||
| + | if (newValue != CotxeEstats.ATURAT) { | ||
| + | this.setGasolina(this.gasolina - 1); | ||
| + | } | ||
| + | if (this.gasolina > 0) { | ||
| + | this.estat = newValue; | ||
| + | llistaObservers.firePropertyChange(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | public void setGasolina (int newValue) { | ||
| + | int oldValue = this.gasolina; | ||
| + | if (newValue > 0) { | ||
| + | this.gasolina = newValue; | ||
| + | } else { | ||
| + | this.gasolina = 0; | ||
| + | this.setEstat(CotxeEstats.ATURAT); | ||
| + | } | ||
| + | if (oldValue != this.gasolina) { | ||
| + | llistaObservers.firePropertyChange(" | ||
| + | } | ||
| + | } | ||
| + | } | ||
| + | |||
| + | </ | ||
| + | |||
| + | == Exemple de Observer == | ||
| + | |||
| + | {{ :: | ||