|
| 1 | +--- |
| 2 | +title: Abstract Factory |
| 3 | +category: Creational |
| 4 | +language: it |
| 5 | +tag: |
| 6 | + - Gang of Four |
| 7 | +--- |
| 8 | + |
| 9 | +## Anche conosciuto come |
| 10 | + |
| 11 | +Kit |
| 12 | + |
| 13 | +## Intento |
| 14 | + |
| 15 | +Fornire un'interfaccia per la creazione di famiglie di oggetti correlati o dipendenti senza specificarne le classi concrete. |
| 16 | + |
| 17 | +## Spiegazione |
| 18 | + |
| 19 | +Esempio del mondo reale |
| 20 | + |
| 21 | +> Per creare un regno, abbiamo bisogno di oggetti con un tema comune. Il regno elfico ha bisogno di un re elfico, di un castello elfico e di un esercito elfico, mentre il regno degli orchi ha bisogno di un re degli orchi, di un castello degli orchi e di un esercito degli orchi. Esiste una dipendenza tra gli oggetti all'interno del regno. |
| 22 | +
|
| 23 | +In parole semplici |
| 24 | + |
| 25 | +> Una fabbrica di fabbriche; una fabbrica che raggruppa le singole fabbriche correlate o dipendenti senza specificare le loro classi concrete. |
| 26 | +
|
| 27 | +Wikipedia dice |
| 28 | + |
| 29 | +> L'Abstract Factory fornisce un'interfaccia per creare famiglie di oggetti connessi o dipendenti tra loro, in modo che non ci sia necessità da parte dei client di specificare i nomi delle classi concrete all'interno del proprio codice. |
| 30 | +
|
| 31 | +**Esempio di codice** |
| 32 | + |
| 33 | +Traducendo l'esempio del regno sopra. Prima di tutto, abbiamo alcune interfacce e implementazioni per gli oggetti all'interno del regno. |
| 34 | + |
| 35 | +```java |
| 36 | +public interface Castle { |
| 37 | + String getDescription(); |
| 38 | +} |
| 39 | + |
| 40 | +public interface King { |
| 41 | + String getDescription(); |
| 42 | +} |
| 43 | + |
| 44 | +public interface Army { |
| 45 | + String getDescription(); |
| 46 | +} |
| 47 | + |
| 48 | +// Elven implementations -> |
| 49 | +public class ElfCastle implements Castle { |
| 50 | + static final String DESCRIPTION = "This is the elven castle!"; |
| 51 | + @Override |
| 52 | + public String getDescription() { |
| 53 | + return DESCRIPTION; |
| 54 | + } |
| 55 | +} |
| 56 | +public class ElfKing implements King { |
| 57 | + static final String DESCRIPTION = "This is the elven king!"; |
| 58 | + @Override |
| 59 | + public String getDescription() { |
| 60 | + return DESCRIPTION; |
| 61 | + } |
| 62 | +} |
| 63 | +public class ElfArmy implements Army { |
| 64 | + static final String DESCRIPTION = "This is the elven Army!"; |
| 65 | + @Override |
| 66 | + public String getDescription() { |
| 67 | + return DESCRIPTION; |
| 68 | + } |
| 69 | +} |
| 70 | + |
| 71 | +// Orcish implementations similarly -> ... |
| 72 | + |
| 73 | +``` |
| 74 | + |
| 75 | +Successivamente, abbiamo l'astrazione e le implementazioni per la fabbrica del regno. |
| 76 | + |
| 77 | +```java |
| 78 | +public interface KingdomFactory { |
| 79 | + Castle createCastle(); |
| 80 | + King createKing(); |
| 81 | + Army createArmy(); |
| 82 | +} |
| 83 | + |
| 84 | +public class ElfKingdomFactory implements KingdomFactory { |
| 85 | + |
| 86 | + @Override |
| 87 | + public Castle createCastle() { |
| 88 | + return new ElfCastle(); |
| 89 | + } |
| 90 | + |
| 91 | + @Override |
| 92 | + public King createKing() { |
| 93 | + return new ElfKing(); |
| 94 | + } |
| 95 | + |
| 96 | + @Override |
| 97 | + public Army createArmy() { |
| 98 | + return new ElfArmy(); |
| 99 | + } |
| 100 | +} |
| 101 | + |
| 102 | +public class OrcKingdomFactory implements KingdomFactory { |
| 103 | + |
| 104 | + @Override |
| 105 | + public Castle createCastle() { |
| 106 | + return new OrcCastle(); |
| 107 | + } |
| 108 | + |
| 109 | + @Override |
| 110 | + public King createKing() { |
| 111 | + return new OrcKing(); |
| 112 | + } |
| 113 | + |
| 114 | + @Override |
| 115 | + public Army createArmy() { |
| 116 | + return new OrcArmy(); |
| 117 | + } |
| 118 | +} |
| 119 | +``` |
| 120 | + |
| 121 | +Ora abbiamo la fabbrica astratta che ci consente di creare una famiglia di oggetti correlati, ad esempio la fabbrica del regno elfico crea il castello elfico, il re elfico e l'esercito elfico, ecc. |
| 122 | + |
| 123 | +```java |
| 124 | +var factory = new ElfKingdomFactory(); |
| 125 | +var castle = factory.createCastle(); |
| 126 | +var king = factory.createKing(); |
| 127 | +var army = factory.createArmy(); |
| 128 | + |
| 129 | +castle.getDescription(); |
| 130 | +king.getDescription(); |
| 131 | +army.getDescription(); |
| 132 | +``` |
| 133 | + |
| 134 | +Output del programma: |
| 135 | + |
| 136 | +```java |
| 137 | +This is the elven castle! |
| 138 | +This is the elven king! |
| 139 | +This is the elven Army! |
| 140 | +``` |
| 141 | + |
| 142 | +Ora possiamo progettare una fabbrica per le nostre diverse fabbriche di regni. In questo esempio, abbiamo creato `FactoryMaker`, responsabile di restituire un'istanza di `ElfKingdomFactory` o `OrcKingdomFactory`. |
| 143 | +Il client può utilizzare `FactoryMaker` per creare la fabbrica concreta desiderata, che a sua volta produrrà diversi oggetti concreti (derivati da `Army`, `King`, `Castle`). |
| 144 | +In questo esempio, abbiamo anche utilizzato un enum per parametrizzare il tipo di fabbrica di regno richiesto dal client. |
| 145 | + |
| 146 | +```java |
| 147 | +public static class FactoryMaker { |
| 148 | + |
| 149 | + public enum KingdomType { |
| 150 | + ELF, ORC |
| 151 | + } |
| 152 | + |
| 153 | + public static KingdomFactory makeFactory(KingdomType type) { |
| 154 | + return switch (type) { |
| 155 | + case ELF -> new ElfKingdomFactory(); |
| 156 | + case ORC -> new OrcKingdomFactory(); |
| 157 | + default -> throw new IllegalArgumentException("KingdomType not supported."); |
| 158 | + }; |
| 159 | + } |
| 160 | +} |
| 161 | + |
| 162 | + public static void main(String[] args) { |
| 163 | + var app = new App(); |
| 164 | + |
| 165 | + LOGGER.info("Elf Kingdom"); |
| 166 | + app.createKingdom(FactoryMaker.makeFactory(KingdomType.ELF)); |
| 167 | + LOGGER.info(app.getArmy().getDescription()); |
| 168 | + LOGGER.info(app.getCastle().getDescription()); |
| 169 | + LOGGER.info(app.getKing().getDescription()); |
| 170 | + |
| 171 | + LOGGER.info("Orc Kingdom"); |
| 172 | + app.createKingdom(FactoryMaker.makeFactory(KingdomType.ORC)); |
| 173 | + --similar use of the orc factory |
| 174 | + } |
| 175 | +``` |
| 176 | + |
| 177 | +## Diagramma delle classi |
| 178 | + |
| 179 | + |
| 180 | + |
| 181 | + |
| 182 | +## Applicabilità |
| 183 | + |
| 184 | +Utilizza il pattern Abstract Factory quando |
| 185 | + |
| 186 | +* Il sistema deve essere indipendente dal modo in cui i suoi prodotti vengono creati, composti e rappresentati. |
| 187 | +* Il sistema deve essere configurato con una delle molteplici famiglie di prodotti. |
| 188 | +* La famiglia di oggetti di prodotto correlati è progettata per essere utilizzata interamente, e hai bisogno di imporre questo presupposto. |
| 189 | +* Vuoi fornire una libreria di classi di prodotto e vuoi esporre solo le loro interfacce, non le loro implementazioni. |
| 190 | +* Il tempo di vita della dipendenza è concettualmente più breve di quella del consumer. |
| 191 | +* Hai bisogno di un valore di runtime per costruire una particolare dipendenza. |
| 192 | +* Vuoi decidere quale prodotto chiamare da una famiglia a runtime. |
| 193 | +* Devi fornire uno o più parametri conosciuti solo a runtime prima di poter risolvere una dipendenza. |
| 194 | +* Hai bisogno di coerenza tra i prodotti. |
| 195 | +* Non vuoi modificare il codice esistente quando aggiungi nuovi prodotti o famiglie di prodotti al programma. |
| 196 | + |
| 197 | +Esempi di casi d'uso |
| 198 | + |
| 199 | +* Selezionare la chiamata all'implementazione appropriata di FileSystemAcmeService o DatabaseAcmeService o NetworkAcmeService in fase di esecuzione. |
| 200 | +* La scrittura di casi di unit test diventa molto più semplice. |
| 201 | +* Strumenti UI per diversi sistemi operativi. |
| 202 | + |
| 203 | +## Conseguenze |
| 204 | + |
| 205 | +* La dependency injection in Java nasconde le dipendenze delle classi di servizio, il che può portare a errori a runtime che sarebbero stati rilevati in fase di compilazione. |
| 206 | +* Se da un lato il pattern è ottimo per la creazione di oggetti predefiniti, l'aggiunta di nuovi oggetti potrebbe essere complicato. |
| 207 | +* Il codice diventa più complesso di quanto dovrebbe essere, poiché vengono introdotte molte nuove interfacce e classi insieme al pattern. |
| 208 | + |
| 209 | +## Tutorial |
| 210 | + |
| 211 | +* [Abstract Factory Pattern Tutorial](https://www.journaldev.com/1418/abstract-factory-design-pattern-in-java) |
| 212 | + |
| 213 | +## Usi noti |
| 214 | + |
| 215 | +* [javax.xml.parsers.DocumentBuilderFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/parsers/DocumentBuilderFactory.html) |
| 216 | +* [javax.xml.transform.TransformerFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/transform/TransformerFactory.html#newInstance--) |
| 217 | +* [javax.xml.xpath.XPathFactory](http://docs.oracle.com/javase/8/docs/api/javax/xml/xpath/XPathFactory.html#newInstance--) |
| 218 | + |
| 219 | +## Pattern correlati |
| 220 | + |
| 221 | +* [Factory Method](https://java-design-patterns.com/patterns/factory-method/) |
| 222 | +* [Factory Kit](https://java-design-patterns.com/patterns/factory-kit/) |
| 223 | + |
| 224 | +## Collegamenti esterni |
| 225 | + |
| 226 | +* [Design Patterns: Elements of Reusable Object-Oriented Software](https://www.amazon.com/gp/product/0201633612/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0201633612&linkCode=as2&tag=javadesignpat-20&linkId=675d49790ce11db99d90bde47f1aeb59) |
| 227 | +* [Head First Design Patterns: A Brain-Friendly Guide](https://www.amazon.com/gp/product/0596007124/ref=as_li_tl?ie=UTF8&camp=1789&creative=9325&creativeASIN=0596007124&linkCode=as2&tag=javadesignpat-20&linkId=6b8b6eea86021af6c8e3cd3fc382cb5b) |
0 commit comments