Kreatiewe patrone is vir die eerste keer beskryf in die bekende Gang of Four's Die boek bied elke patroon in 'n toegewyde hoofstuk voor en volg 'n streng struktuur vir elkeen: bedoeling, motivering, toepasbaarheid, struktuur, deelnemers, samewerking, gevolge, implementering, monster kode, bekende gebruik, en verwante patrone. Ontwerppatrone Hier is 'n uitdrukking vir die Die patroon: bouer Die poging: Skei die konstruksie van 'n komplekse voorwerp van sy verteenwoordiging sodat dieselfde konstruksieproses verskillende verteenwoordigings kan skep. Die toepasbaarheid: Gebruik die bouerpatroon wanneer die algoritme vir die skep van 'n komplekse voorwerp moet onafhanklik wees van die dele wat die voorwerp maak en hoe hulle versamel word. die konstruksieproses moet verskillende verteenwoordigings vir die voorwerp wat gebou word, toelaat. : Intent Skei die konstruksie van 'n komplekse voorwerp van sy verteenwoordiging sodat dieselfde konstruksieproses verskillende verteenwoordigings kan skep. : Applicability Gebruik die bouerpatroon wanneer die algoritme vir die skep van 'n komplekse voorwerp moet onafhanklik wees van die dele wat die voorwerp maak en hoe hulle versamel word. die konstruksieproses moet verskillende verteenwoordigings vir die voorwerp wat gebou word, toelaat. Die GoF (Gang of Four) was fundamenteel in die domein van Object-Oriented Programming en het die ontwerp van programmeertaal beïnvloed, insluitend wydverspreide soos Java. Terwyl ek weer in 'n ingenieursposisie is, kom ek oor onlangs geskrewe Java-kode wat baie verbetering potensiaal met betrekking tot onderhoubaarheid het. Dit werk, maar ek dink dat ingenieurs dit moet opdater, insluitend die oorspronklike skrywer se toekomstige self en ek, en ek is seker ek kan hulle help. Hierdie week het ek kode hervorm deur kreatiewe patrone te gebruik om sy onderhoubaarheid te verbeter. 'N Constructor met baie parameters van dieselfde tipe. Kom ons dink aan 'n konstruksie met baie String-parameters: public License ( String id, String licenseeName, String licenseId, String environment, LocalDateTime generatedAt ) By die oproep van hierdie konstruksie, is die kans dat die oproeper onwillekeurig parameter bestellings kan skakel: var license = new License("My license", "XXX-123", "Customer", "User-acceptance tests", new LocalDateTime()); Oops, ek het die lisensie-naam en die lisensie-ID verander. jou IDE kan hier help, maar daar is ander maniere. Soorte wrapers Voorstanders van suiwer OOP sal gelukkig daarop wijs dat 'n mens nooit direk 'n string moet gebruik nie. Die Java : Ek het g. record public record Id(String id) { ... } public record LicenseeName(String licenseeName) { ... } public record LicenseeId(String licenseId) { ... } public record Environment(String environment) { ... } public record GeneratedAt(LocalDateTime generatedAt) { ... } Ons kan nie 'n fout maak nie: var id = new Id("My license"); var licenseeName = new LicenseeName("Customer"); var licenseId = new LicenseeId("XXX-123"); var environment = new Environment("User-acceptance tests"); var generatedAt = new LocalDateTime(); var license = new License(id, licenseId, licenseName, environment, generatedAt); //1 Verwysingsfout Terwyl hierdie benadering beslis die onderhoubaarheid verbeter, verhoog die wrapper die geheue grootte. Die presiese toename hang af van die JDK implementasie, maar vir 'n enkele tipe is dit ongeveer 5 keer groter. Kotlin maak dit 'n wind deur die verskaffing van : die verpakking is 'n kompile-tydskoers, maar die bytecode dui op die verpakte tipe met die volgende beperking: Inline waarde klasse 'N Inline-klas moet 'n enkele eiendom hê wat in die primêre konstruktors geïnifiseer is. 'N Inline-klas moet 'n enkele eiendom hê wat in die primêre konstruktors geïnifiseer is. Parameters genoem Java bied slegs metodeoproepe met posisionele parameters, maar ander tale, , Python, Kotlin, en Rust, bied ook genoemde parameters. Ek het g. Hier is 'n Kotlin konstruksie wat die bovenstaande klas weerspieël: class License ( val id: String, val licenseeName: String, val licenseId: String, val environment: String, val generatedAt: LocalDateTime ) Jy kan die bouer noem deur die parameters te noem, wat die risiko's van 'n fout verminder: val license = License( id = "My license", licenseeName = "Customer", licenseId = "XXX-123", environment = "User-acceptance tests", generatedAt = LocalDateTime() ) die Die patroon bouer die patroon is nog 'n lewensvatbare benadering, selfs al is dit nie deel van die gebruik gevalle wat in die GoF beskryf word nie. bouer Hier is die kode: public class License { private final String id; private final String licenseeName; private final String licenseId; private final String environment; private final LocalDateTime generatedAt; private License ( //1 String id, String licenseeName, String licenseId, String environment, LocalDateTime generatedAt ) { ... } public static LicenseBuilder builder() { //2 return new LicenseBuilder(); } public static class LicenseBuilder { private String id; //3 private String licenseeName; //3 private String licenseId; //3 private String environment; //3 private LocalDateTime generatedAt; //3 private LicenseBuilder() {} //1 public LicenseBuilder withId(String id) { //4 this.id = id; //5 return this; //4 } // Other `withXXX` methods public License build() { //6 return new License( id, licenseeName, licenseId, environment, generatedAt ); } } } Voorkom direkte objek instantiasie Maak 'n nuwe bouer Die bouervelde imiteer die velde van die voorwerp Elke metode gee die bouer-object self terug Verwys na die attribuut Terugkeer die volledige voorwerp Een kan nou die bouer so noem: val license = License.builder() .withId("My license") .withLicenseName("Customer") .withLicenseId("XXX-123") .withEnvironment("User-acceptance tests") .withGeneratedAt(new LocalDateTime()) Die skep van die bouer kode is 'n pyn (as jy nie AI gebruik nie), maar dit laat 'n beter leesbaarheid toe.Daarbenewens kan 'n validering vir elke metodeoproep byvoeg word, wat verseker dat die voorwerp in konstruksie geldig is. . Gevolgde bouer Samenvatting Approach Pros Cons Type wrappers Object-Oriented Programming - More verbose- Can be memory-heavy depending on the language Named parameters Easy Not available in Java Builder pattern Verbose - Allows creating complex objects- Allows validating Soorte wrapers Object-georiënteerde programmering - Meer verbose- Kan geheue-swaar wees afhangende van die taal Parameters genoem maklik Nie beskikbaar in Java nie Die bouer patroon Verboseer - Toelaat om komplekse voorwerpe te skep- Toelaat om te valideer Vervaardigers gooi uitsonderings In dieselfde codebase het ek die volgende kode gevind: public Stuff(UuidService uuidService, FallbackUuidService fallbackUuidService) { try { uuid = uuidService.getUuid(); } catch(CannotGetUuidException e) { try { uuid = fallbackUuidService.getUuid(); } catch(CannotGetUuidException e1) { uuid = "UUID can be fetched"; } } } Met 'n klein aantal ervaring, kan jy sien wat verkeerd is in die bovenstaande snippet. is inisialiseer met 'n string wat nie 'n UUID is nie. Alle kode wat op UUID vertrou, moet met moontlik nie-UUID-waardes hanteer. Een moet vinnig misluk. 'n vinnige oplossing sal lyk soos hierdie: uuid public Stuff(UuidService uuidService, FallbackUuidService fallbackUuidService) { try { uuid = uuidService.getUuid(); } catch(CannotGetUuidException e) { try { uuid = fallbackUuidService.getUuid(); } catch(CannotGetUuidException e1) { throw new RuntimeException(e1); } } } Nou, elke Object het 'n geldige UUID. Maar die gooi van uitsonderings binne konstruktors het potensiële probleme: Stuff Resource Leaks: As die bouer hulpbronne (bv. lêers, sockets) toewys en 'n uitsondering gooi, kan daardie hulpbronne nie vrygelaat word nie. Erfenis: As 'n superklas bouer 'n uitsondering gooi, sal die subklas bouer nie hardloop nie. Gecontroleerde uitsonderings: Dit is onmoontlik om gekontroleerde uitsonderings in konstruktors te gebruik, slegs die runtime. Om hierdie redes dink ek dat uitsonderings nie hul plek in konstruktors het nie en ek vermy hulle. patroon beskryf in die eerste afdeling, maar soos genoem, dit is 'n baie kode; Ek dink nie dit is nodig nie. . bouer Fabriekmetode Probeer Definieer 'n koppelvlak vir die skep van 'n voorwerp, maar laat subklasse besluit watter klasse te instantiate. toepasbaarheid Gebruik die fabrieksmetode patroon wanneer: 'n Klas kan nie die klas van voorwerpe voorspel wat dit moet skep nie. 'n Klas wil hê dat sy subklasse die voorwerpe wat dit skep, spesifiseer. Klasse oordra verantwoordelikheid aan een van verskeie helper-onderklasse, en jy wil die kennis van watter helper-onderklasse die deelnemer is, lokaliser. Intent Definieer 'n koppelvlak vir die skep van 'n voorwerp, maar laat subklasse besluit watter klasse te instantiate. Applicability Gebruik die fabrieksmetode patroon wanneer: 'n Klas kan nie die klas van voorwerpe voorspel wat dit moet skep nie. 'n Klas wil hê dat sy subklasse die voorwerpe wat dit skep, spesifiseer. Klasse oordra verantwoordelikheid aan een van verskeie helper-onderklasse, en jy wil die kennis van watter helper-onderklasse die deelnemer is, lokaliser. Let daarop dat ons dit in hierdie geval vir 'n ander rede gebruik. hier is die geactualiseerde kode: public class Stuff { private final UUID uuid; private Stuff(UUID uuid) { //1 this.uuid = uuid; } public static Stuff create(UuidService uuidService, FallbackUuidService fallbackUuidService) throws CannotGetUuidException { try { return new Stuff(uuidService.getUuid()); } catch(CannotGetUuidException e) { return new Stuff(fallbackUuidService.getUuid()); //2 } } } Vermy buitelandse instantiasie As dit misluk, gooi dit 'n nuwe CannotGetUuidException Een noem die boonste so: var stuff = Stuff.create(uuidService, fallbackUuidService); //1 nodig om te vang CannotGetUuidException Op hierdie punt is ons seker dat die voorwerp ten volle geïmplementeer word as die oproep suksesvol is. Konklusie In hierdie pos het ek twee gebruik van die GoF se kreatiewe patrone beskryf, wat nie in die boek vermeld word nie: verbetering van onderhoubaarheid en verseker dat voorwerpe ten volle geïmplementeer word. To go further: GoF ontwerppatrone 'N duik in die bouer patroon Die bouerpatroon is 'n eindige toestandsmasjien! Oorspronklik gepubliseer by A Java Geek op Augustus 31st, 2025 'n Java geek