Introducció al Patró Composite
El patró Composite és un patró estructural que permet tractar objectes individuals i composicions d'objectes de manera uniforme. Aquest patró és especialment útil quan es treballa amb estructures d'arbres, com ara jerarquies d'objectes.
Objectius del Patró Composite
- Uniformitat: Permet tractar objectes individuals i grups d'objectes de la mateixa manera.
- Flexibilitat: Facilita l'addició de nous tipus de components sense canviar el codi existent.
- Simplicitat: Redueix la complexitat del codi client que treballa amb estructures jeràrquiques.
Components del Patró Composite
El patró Composite consta de tres components principals:
- Component: Defineix la interfície per als objectes de la composició.
- Leaf (Fulla): Representa objectes individuals de la composició.
- Composite: Representa composicions d'objectes (pot contenir altres fulles o composicions).
Diagrama UML del Patró Composite
Component + operation() Leaf + operation() Composite + add(Component) + remove(Component) + getChild(int) + operation()
Implementació del Patró Composite
A continuació es mostra una implementació del patró Composite en Java:
Component
Leaf
public class Leaf extends Component {
@Override
public void operation() {
System.out.println("Leaf operation");
}
}Composite
import java.util.ArrayList;
import java.util.List;
public class Composite extends Component {
private List<Component> children = new ArrayList<>();
public void add(Component component) {
children.add(component);
}
public void remove(Component component) {
children.remove(component);
}
public Component getChild(int index) {
return children.get(index);
}
@Override
public void operation() {
for (Component child : children) {
child.operation();
}
}
}Exemple d'Ús
public class Client {
public static void main(String[] args) {
Composite root = new Composite();
Composite branch1 = new Composite();
Composite branch2 = new Composite();
Leaf leaf1 = new Leaf();
Leaf leaf2 = new Leaf();
Leaf leaf3 = new Leaf();
root.add(branch1);
root.add(branch2);
branch1.add(leaf1);
branch1.add(leaf2);
branch2.add(leaf3);
root.operation();
}
}Explicació del Codi
- Component: Defineix l'operació comuna que tots els components han d'implementar.
- Leaf: Implementa l'operació definida en el component.
- Composite: Conté una llista de components i implementa l'operació recorrent tots els seus fills.
- Client: Crea una estructura jeràrquica de components i invoca l'operació en la composició arrel.
Exercicis Pràctics
Exercici 1: Implementació Bàsica
Implementa una estructura jeràrquica utilitzant el patró Composite per representar un sistema de fitxers amb carpetes i arxius. Cada carpeta pot contenir altres carpetes o arxius, i cada arxiu ha de tenir una operació per mostrar el seu nom.
Solució
public abstract class FileSystemComponent {
public abstract void showDetails();
}
public class File extends FileSystemComponent {
private String name;
public File(String name) {
this.name = name;
}
@Override
public void showDetails() {
System.out.println("File: " + name);
}
}
public class Directory extends FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();
public Directory(String name) {
this.name = name;
}
public void add(FileSystemComponent component) {
components.add(component);
}
public void remove(FileSystemComponent component) {
components.remove(component);
}
@Override
public void showDetails() {
System.out.println("Directory: " + name);
for (FileSystemComponent component : components) {
component.showDetails();
}
}
}
public class Client {
public static void main(String[] args) {
Directory root = new Directory("root");
Directory home = new Directory("home");
Directory user = new Directory("user");
File file1 = new File("file1.txt");
File file2 = new File("file2.txt");
File file3 = new File("file3.txt");
root.add(home);
home.add(user);
user.add(file1);
user.add(file2);
root.add(file3);
root.showDetails();
}
}Exercici 2: Extensió del Patró
Extén l'exemple anterior per afegir permisos de lectura i escriptura als arxius i carpetes. Implementa mètodes per verificar aquests permisos abans de mostrar els detalls.
Solució
public abstract class FileSystemComponent {
protected boolean canRead;
protected boolean canWrite;
public FileSystemComponent(boolean canRead, boolean canWrite) {
this.canRead = canRead;
this.canWrite = canWrite;
}
public abstract void showDetails();
}
public class File extends FileSystemComponent {
private String name;
public File(String name, boolean canRead, boolean canWrite) {
super(canRead, canWrite);
this.name = name;
}
@Override
public void showDetails() {
if (canRead) {
System.out.println("File: " + name);
} else {
System.out.println("File: " + name + " (No read permission)");
}
}
}
public class Directory extends FileSystemComponent {
private String name;
private List<FileSystemComponent> components = new ArrayList<>();
public Directory(String name, boolean canRead, boolean canWrite) {
super(canRead, canWrite);
this.name = name;
}
public void add(FileSystemComponent component) {
components.add(component);
}
public void remove(FileSystemComponent component) {
components.remove(component);
}
@Override
public void showDetails() {
if (canRead) {
System.out.println("Directory: " + name);
for (FileSystemComponent component : components) {
component.showDetails();
}
} else {
System.out.println("Directory: " + name + " (No read permission)");
}
}
}
public class Client {
public static void main(String[] args) {
Directory root = new Directory("root", true, true);
Directory home = new Directory("home", true, false);
Directory user = new Directory("user", false, true);
File file1 = new File("file1.txt", true, true);
File file2 = new File("file2.txt", true, false);
File file3 = new File("file3.txt", false, true);
root.add(home);
home.add(user);
user.add(file1);
user.add(file2);
root.add(file3);
root.showDetails();
}
}Resum
El patró Composite és una solució poderosa per treballar amb estructures jeràrquiques, permetent tractar objectes individuals i composicions d'objectes de manera uniforme. Aquest patró és especialment útil en aplicacions que requereixen treballar amb estructures d'arbres, com ara sistemes de fitxers, menús i organitzacions jeràrquiques.
Curs de Patrons de Disseny de Programari
Mòdul 1: Introducció als Patrons de Disseny
- Què són els Patrons de Disseny?
- Història i Origen dels Patrons de Disseny
- Classificació dels Patrons de Disseny
- Avantatges i Desavantatges d'Usar Patrons de Disseny
Mòdul 2: Patrons Creacionals
Mòdul 3: Patrons Estructurals
Mòdul 4: Patrons de Comportament
- Introducció als Patrons de Comportament
- Chain of Responsibility
- Command
- Interpreter
- Iterator
- Mediator
- Memento
- Observer
- State
- Strategy
- Template Method
- Visitor
Mòdul 5: Aplicació de Patrons de Disseny
- Com Seleccionar el Patró Adequat
- Exemples Pràctics d'Ús de Patrons
- Patrons de Disseny en Projectes Reals
- Refactorització Usant Patrons de Disseny
Mòdul 6: Patrons de Disseny Avançats
- Patrons de Disseny en Arquitectures Modernes
- Patrons de Disseny en Microserveis
- Patrons de Disseny en Sistemes Distribuïts
- Patrons de Disseny en Desenvolupament Àgil
