Introduktion til AutoFactory

1. Introduktion

I denne vejledning giver vi en kort introduktion til Autofabrik, fra af Google.

Dette er en kodegenerator på kildeniveau, der hjælper med at generere fabrikker.

2. Maven-opsætning

Før vi begynder, lad os tilføje følgende afhængighed af pom.xml:

 com.google.auto.factory auto-fabrik 1.0-beta5 

Den seneste version kan findes her.

3. Hurtigstart

Lad os nu se hurtigt på hvad Autofabrik kan gøre og oprette en simpel telefon klasse.

Så når vi kommenterer telefon klasse med @AutoFactory og dens konstruktørparameter med @Stillet til rådighed, vi får:

@AutoFactory offentlig klasse Telefon {privat endelig Kamera kamera; privat final String otherParts; PhoneAssembler (@ Provided Camera camera, String otherParts) {this.camera = kamera; this.otherParts = otherParts; } // ...}

Vi brugte kun to kommentarer: @AutoFactory og @Stillet til rådighed. Når vi har brug for en fabrik, der er genereret til vores klasse, kan vi kommentere den med @AutoFactory, der henviser til @Stillet til rådighed gælder for konstruktorparametre i denne klasse, og det betyder, at den kommenterede parameter skal leveres af en injiceret Udbyder.

I uddraget ovenfor forventer vi, at Kamera leveres af enhver kameraproducent og Autofabrik hjælper med at generere følgende kode:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse PhoneFactory {privat final Udbyder cameraProvider; @Inject PhoneAssemblerFactory (Provider cameraProvider) {this.cameraProvider = checkNotNull (cameraProvider, 1); } PhoneAssembler create (String otherParts) {returner ny PhoneAssembler (checkNotNull (cameraProvider.get (), 1), checkNotNull (otherParts, 2)); } // ...}

Nu har vi en Telefonfabrik genereres automatisk af Autofabrik på kompileringstidspunktet, og vi kan bruge det til at producere telefonforekomster:

PhoneFactory phoneFactory = ny PhoneFactory (() -> nyt kamera ("Ukendt", "XXX")); Telefon simplePhone = phoneFactory.create ("andre dele");

Det @AutoFactory kommentar kan også anvendes på konstruktører:

offentlig klasse ClassicPhone {privat endelig String-tastatur; privat finale String ringetone; private String andreDele; @AutoFactory offentlig ClassicPhone (@Provided String dialpad, @Provided String ringer) {this.dialpad = dialpad; this.ringer = ringetone; } @ AutoFactory offentlig ClassicPhone (String otherParts) {dette ("defaultDialPad", "defaultRinger"); this.otherParts = otherParts; } // ...}

I uddraget ovenfor anvendte vi @AutoFactory til begge konstruktører. Autofabrik vil simpelthen generere to oprettelsesmetoder for os i overensstemmelse hermed:

@Generated (værdi = "com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse ClassicPhoneFactory {privat final Udbyder java_lang_StringProvider; @Inject public ClassicPhoneFactory (Provider java_lang_StringProvider) {this.java_lang_StringProvider = checkNotNull (java_lang_StringProvider, 1); } public ClassicPhone create () {return new ClassicPhone (checkNotNull (java_lang_StringProvider.get (), 1), checkNotNull (java_lang_StringProvider.get (), 2)); } offentlig ClassicPhone-oprettelse (String otherParts) {returner ny ClassicPhone (checkNotNull (otherParts, 1)); } // ...}

Autofabrik understøtter også parametre, der er kommenteret med @Stillet til rådighed, men kun til JSR-330-kommentarer.

For eksempel hvis vi vil have cameraProvider for at være “Sony” kan vi ændre telefon klasse til:

@AutoFactory offentlig klasse Telefon {PhoneAssembler (@Provided @Named ("Sony") Kamera kamera, String andre dele) {this.camera = kamera; this.otherParts = otherParts; } // ...}

AutoFactory bevarer @Som hedder@Kvalifikator så vi f.eks. kan bruge det, når vi bruger Dependency Injection rammer:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse PhoneFactory {privat final Udbyder cameraProvider; @Inject PhoneAssemblerFactory (@Named ("Sony") Udbyder cameraProvider) {this.cameraProvider = checkNotNull (cameraProvider, 1); } // ...}

4. Tilpasset kodegenerering

Der er flere attributter, vi kan bruge sammen med @AutoFactory kommentar for at tilpasse den genererede kode.

4.1. Brugerdefineret klasse navn

Navnet på den genererede fabriksklasse kan indstilles med className:

@AutoFactory (className = "SamsungFactory") offentlig klasse SmartPhone {// ...}

Med konfigurationen ovenfor opretter vi en klasse med navnet SamsungFabrik:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse SamsungFactory {// ...}

4.2. ikke-endelig Fabrikker

Bemærk, at den genererede fabrikklasse er markeret som standard som standard, så vi kan ændre denne adfærd ved at indstille allowSubclasses attribut til falsk:

@AutoFactory (className = "SamsungFactory", allowSubclasses = sand) offentlig klasse SmartPhone {// ...}

Nu har vi:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig klasse SamsungFactory {// ...}

4.3. Flere muligheder

Derudover kan vi specificere en liste over grænseflader, som den genererede fabrik kan implementere ved hjælp af “implementering ”parameter.

Her har vi brug for SamsungFabrik til at producere smartphones med brugerdefineret lagerplads:

offentlig grænseflade CustomStorage {SmartPhone customROMInGB (int romSize); }

Bemærk, at metoder i grænsefladen skal returnere forekomster af baseklassen SmartPhone.

Derefter for at generere en fabriksklasse med grænsefladen ovenfor implementeret, Autofabrik kræver relevante konstruktører i basisklassen:

@AutoFactory (className = "SamsungFactory", allowSubclasses = true, implementering = CustomStorage.class) offentlig klasse SmartPhone {offentlig SmartPhone (int romSize) {// ...} // ...}

Dermed, Autofabrik genererer følgende kode:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig klasse SamsungFactory implementerer CustomStorage {// ... public SmartPhone create (int romSize) {returner ny SmartPhone (romSize); } @ Override offentlig SmartPhone customROMInGB (int romSize) {return create (romSize); }}

4.4. Fabrikker med udvidelser

Siden Autofabrik kan generere interfaceimplementeringer, er det naturligt at forvente, at det også kan udvide klasser, og dette er faktisk muligt:

offentlig abstrakt klasse AbstractFactory {abstrakt CustomPhone newInstance (String brand); } @AutoFactory (udvidet = AbstractFactory.class) offentlig klasse CustomPhone {privat final String brand; offentlig CustomPhone (String brand) {this.brand = brand; }}

Her udvidede vi AbstraktFabrik klasse ved hjælp af udvider. Det skal vi også bemærk, at hver abstrakt metode i basis abstrakt klasse (AbstraktFabrik) skal have en tilsvarende konstruktør i betonklassen (CustomPhone).

Endelig kan vi se følgende genererede kode:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse CustomPhoneFactory udvider AbstractFactory {@Inject public CustomPhoneFactory () {} public CustomPhone create (String brand) {return new CustomPhone (checkNotNull (brand, 1) ); } @ Override public CustomPhone newInstance (String brand) {return create (brand); } // ...}

Det kan vi se Autofabrik er smart nok til at gøre brug af konstruktøren til at implementere den tilsvarende abstrakte metode - gode funktioner som denne i Autofabrik vil helt sikkert spare os masser af tid og kode.

5. Autofabrik Med Guice

Som vi nævnte tidligere i denne artikel, Autofabrik understøtter JSR-330-annoteringer, så vi kan integrere eksisterende afhængighedsinjektionsramme med det.

Lad os først tilføje Guice til pom.xml:

 com.google.inject guice 4.2.0 

Den seneste version af Guice kan findes her.

Nu demonstrerer vi, hvor godt Autofabrik integreres med Guice.

Da vi forventer, at "Sony" er kameraudbyderen, skal vi indsprøjte en SonyCameraProvider til Telefonfabrik'S konstruktør:

@Generated ("com.google.auto.factory.processor.AutoFactoryProcessor") offentlig endelig klasse PhoneFactory {privat final Udbyder cameraProvider; @Inject public PhoneFactory (@Named ("Sony") Provider cameraProvider) {this.cameraProvider = checkNotNull (cameraProvider, 1); } // ...}

Endelig laver vi bindingen i en Guice modul:

offentlig klasse SonyCameraModule udvider AbstractModule {privat statisk int SONY_CAMERA_SERIAL = 1; @Named ("Sony") @Provides Camera cameraProvider () {returner nyt kamera ("Sony", String.format ("% 03d", SONY_CAMERA_SERIAL ++)); }}

Og vi indstiller kameraleverandøren med kommentarer @Named (“Sony”) i SonyCameraModule at matche Telefonfabrik'S konstruktørparameter.

Nu kan vi se det Guice administrerer afhængighedsindsprøjtning til vores genererede fabrik:

Injektorinjektor = Guice.createInjector (ny SonyCameraModule ()); PhoneFactory injectedFactory = injector.getInstance (PhoneFactory.class); Telefon xperia = injiceretFabrik.create ("Xperia");

6. Under hætten

Alle kommentarer leveret af Autofabrik behandles i kompileringsfasen, som vi har forklaret detaljeret i artiklen: hvordan bearbejdning af kommentar på kildeniveau fungerer.

7. Konklusion

I denne artikel har vi introduceret, hvordan man bruger AutoFactory, og hvordan man integrerer det med Guice - at skrive fabrikker kan være gentagne og fejlbehæftede - kodegenereringsværktøjer som f.eks Autofabrik og AutoVærdi kan spare os for meget tid og frigøre os fra subtile bugs.

Som altid kan den fulde implementering af kodeeksemplerne findes på Github.