RSS

Nie powtarzaj się

Liczba odsłon: 336

Jedną z pod­sta­wo­wych re­guł two­rze­nia opro­gra­mo­wa­nia jest DRY. Nakazuje ona uni­kać po­wie­la­nia ko­du, in­for­mac­ji i de­cy­zji na każ­dym moż­li­wym po­zio­mie. Zazwyczaj ro­zu­mie się ją tyl­ko ja­ko za­kaz sto­so­wa­nia funk­cji „ko­piuj” i „wklej”, za­miast któ­rych na­le­ży do­ko­nać re­fak­to­ry­za­cji ko­du tak, by wspól­ną część prze­nieść do jed­ne­go pod­pro­gra­mu lub kla­sy. Powtarza­nie mo­że jed­nak na­stę­po­wać w wie­lu in­nych punk­tach i na­wet w bar­dzo wąs­kim, wręcz mik­ro­sko­pij­nym za­kre­sie.

Jedną z cech naj­now­szych wer­sji ję­zy­ka Java jest moż­li­wość okre­śla­nia spo­so­bu wy­ko­rzys­ta­nia ele­men­tów pro­gra­mu – klas, pól, me­tod – przez ze­wnętrz­ne bi­blio­te­ki za po­mo­cą ad­no­tac­ji (ang. an­no­ta­tion). Uni­ka się w ten spo­sób po­wszech­ne­go wcześ­niej na­tło­ku zbio­rów kon­fi­gu­ra­cyj­nych XML, któ­re przy­czy­nia­ły się do po­wie­la­nia in­for­mac­ji. Adnotacja znaj­du­je się w tekś­cie źród­ło­wym kla­sy, bez­po­śred­nio przy ele­men­cie, do któ­re­go się od­no­si; sa­mo jej po­ło­że­nie okre­śla ele­ment do­ce­lo­wy.

Nawet, je­że­li za­miast kon­fi­gu­rac­ji XML zacz­nie się w jak naj­szer­szym za­kre­sie sto­so­wać ad­no­ta­cje, moż­na prze­oczyć jesz­cze jed­ną moż­li­wość ogra­ni­cze­nia po­wtó­rzeń w tekś­cie źród­ło­wym pro­gra­mu. Powtórzeń mniej kosz­tow­nych i szkod­li­wych, jed­nak zaw­sze wpro­wa­dza­ją­cych moż­li­wość po­peł­nie­nia błę­du.

1. Nazwy ele­men­tów JAXB

Bibliote­ka JAXB ułat­wia seria­li­zo­wa­nie i de­seria­li­zo­wa­nie zbio­rów XML bez­po­śred­nio z i do klas ję­zy­ka Java:

@XmlRootElement(name = "attribute")
@XmlAccessorType(XmlAccessType.NONE)
public class Attribute {

    @XmlAttribute(name = "name", required = true)
    private String name;

    @XmlAttribute(name = "short", required = false, defaultValue = "false")
    private boolean shortName;

}

Warto jed­nak pa­mię­tać, że bi­blio­te­ka JAXB auto­ma­tycz­nie de­du­ku­je naz­wy ele­men­tów i atry­bu­tów XML na pod­sta­wie nazw klas, pól i ak­ce­so­rów, prze­kształ­ca­jąc je tak, by by­ły pi­sa­ne ma­łą li­te­rą. Przyjmuje też, że każ­dy ele­ment jest nie­obo­wiąz­ko­wy, moż­na za­tem po­mi­nąć nie­któ­re atry­bu­ty name oraz re­quired:

@XmlRootElement
@XmlAccessorType(XmlAccessType.NONE)
public class Attribute {

    @XmlAttribute(required = true)
    private String name;

    @XmlAttribute(name = "short", defaultValue = "false")
    private boolean shortName;

}

Zysk jest po­dwój­ny. Po pierw­sze, moż­na na­pi­sać mniej ko­du i jest on bar­dziej przej­rzy­sty. Po dru­gie, za­po­bie­ga się głu­pim błę­dom, ta­kim jak na przy­kład naz­wa­nie po­la name, lecz seria­li­zo­wa­nie go do po­sta­ci ele­men­tu XML o naz­wie nmae.

2. Nazwy en­cji JPA

Za po­mo­cą me­cha­niz­mu JPA moż­na two­rzyć ta­be­le re­la­cyj­nych baz da­nych oraz trak­to­wać je jak auto­ma­tycz­nie utrwa­la­ne ko­lek­cje da­nych za­wie­ra­ją­ce obiek­ty do­wol­nych klas:

@Entity
@Table(name = "CUSTOMER")
@Access(AccessType.FIELD)
public class Customer implements Serializable {

    @Id
    @Column(name = "ID")
    public long id;

    @Column(name = "FIRST_NAME")
    public String firstName;

}

Warto jed­nak za­pa­mię­tać na­stę­pu­ją­ce re­gu­ły:

  1. Nazwa en­cji jest de­du­ko­wa­na na pod­sta­wie naz­wy kla­sy, zaś naz­wa ta­be­li przyj­mu­je do­myśl­nie war­tość naz­wy en­cji. Jeżeli za­tem naz­wy ta­be­li i kla­sy róż­nią się tyl­ko wiel­koś­cią zna­ków (na któ­rą ba­zy SQL nie zwra­ca­ją uwa­gi), po­da­wa­nie naz­wy wprost jest zbęd­ne. Można wręcz po­mi­nąć ca­łą ad­no­tac­ję @Table.
  2. Nazwa ko­lum­ny jest de­du­ko­wa­na na pod­sta­wie naz­wy po­la. Podawa­nie wprost naz­wy ko­lum­ny jest ko­niecz­ne tyl­ko je­że­li róż­ni się ona od naz­wy po­la. Niestety, stan­dar­dem w ba­zach da­nych są naz­wy z wy­ra­za­mi roz­dzie­lo­ny­mi pod­kreś­le­niem, a me­cha­nizm JPA nie za­wie­ra obec­nie na­rzę­dzia umoż­li­wia­ją­ce­go okreś­le­nie po­li­ty­ki do­sto­so­wy­wa­nia po­sta­ci nazw. W przy­pad­ku pól o wie­lo­wy­ra­zo­wej naz­wie na­le­ży za­tem al­bo okre­ślać naz­wę ko­lum­ny wprost, al­bo na­ru­szać stan­dard na­zew­ni­ctwa pól obo­wią­zu­ją­cy w ję­zy­ku Java.
  3. Wybór po­mię­dzy ad­no­to­wa­niem pól lub cech (ak­ce­so­rów) jest de­du­ko­wa­ny na pod­sta­wie obec­no­ści ad­no­tac­ji. Jeżeli ad­no­to­wa­ne są wy­łącz­nie po­la, do­myśl­nie przyj­mo­wa­ny jest tryb AccessType.FIELD, je­że­li akce­so­ry od­czy­tu — tryb AccessType.PROPERTY. Należy za­cho­wać kon­sek­wen­cję, gdyż od­stęps­twa mo­gą spo­wo­do­wać nie­po­żą­da­ną zmia­nę do­myśl­ne­go try­bu lub zig­no­ro­wa­nie nie­któ­rych ad­no­tac­ji.

Poprzedni przy­kład moż­na za­tem uproś­cić do po­sta­ci:

@Entity
public class Customer implements Serializable {

    @Id
    @Column
    public long id;

    @Column(name = "FIRST_NAME")
    public String firstName;

}

zmniej­sza­jąc na­kład pra­cy, zwięk­sza­jąc przej­rzy­stość tek­stu źród­ło­we­go oraz re­du­ku­jąc (lecz nie lik­wi­du­jąc) ry­zy­ko utra­ty syn­chro­ni­za­cji mię­dzy naz­wa­mi pól i ko­lumn.

3. Nazwy zia­ren CDI

Nazwa ziar­na CDI jest nie­zbęd­na przy two­rze­niu stron WWW wy­ko­rzy­stu­ją­cych me­cha­nizm JSF. Jeżeli na­zwie­my ziar­no:

@Named("pageController")
@ViewScoped
public class PageController implements Serializable {

    public int getValue() {
        return 1;
    }

}

mo­że­my uzys­kać do­stęp do je­go cech przez od­wo­ła­nie po na­rzu­co­nej naz­wie:

Wartość: ${pageController.value}

Adnotacja @Named sa­ma po­tra­fi jed­nak wy­de­du­ko­wać naz­wę ziar­na na pod­sta­wie naz­wy kla­sy, do­ko­nu­jąc za­mia­ny pierw­szej li­te­ry z wiel­kiej (zwyk­łej dla nazw klas) na ma­łą (zwyk­łą dla nazw zmien­nych). Taki sam efekt bę­dzie miał za­tem za­pis:

@Named
@ViewScoped
public class PageController implements Serializable {
    ……

któ­ry rów­nież za­po­bie­ga błę­dom wy­ni­ka­ją­cym z li­te­ró­wek, po­my­łek lub ge­ne­ro­wa­nia ko­du na pod­sta­wie ist­nie­ją­cych szab­lo­nów. Nazwę ziar­na ma sens na­rzu­cać sa­mo­dziel­nie tyl­ko w przy­pad­ku, gdy mu­si się ona róż­nić od naz­wy kla­sy w efek­cie de­cy­zji pro­jek­to­wej lub prze­pro­wa­dza­nej re­fak­to­ry­za­cji.