Accesskontroll på paketnivå

En av de kraftfullaste delarna av objektorienterade språk är deras väl utbyggda stöd för inkapsling (encapsulation). Inkapsling i sin tur är en av de allra viktigaste sakerna att tänka på när man designar och skriver programkod. En applikation som består av komponenter som publicerar rena gränssnitt och gömmer implementationsdetaljer har oerhörda fördelar framför sådana som inte gör det: Man kan utveckla, förstå, testa, debugga, optimera och underhålla komponenterna separat, vilket gör alla dessa saker mycket lättare.

De flesta javautvecklare känner väl till Javas system med modifierarna public, protected och private samt det implicita ”package private” som man får om man inte skriver någon modifierare alls. Modifierarna fungerar olika beroende på var man använder dem någonstans:

Grundtipset när man väljer modifierare är förstås att välja så låg accessnivå som möjligt. På klassnivå bör instinkten således vara att göra alla medlemmar som inte är en del av klassens API private. Endast om klassen är specifikt avsedd för att ärvas från, sätter man lämpliga metoder till protected. Frågan om arvets vara eller inte vara är en historia i sig – kanske kommer det en artikel om det också.

När jag tittar på kod som andra har skrivit, tycker jag att detta tankesätt verkar vara rätt väl inarbetat – på klassnivå. Och här kommer min huvudsakliga poäng.

Men hur tänker man på paketnivå?

Ofta ser man paketstrukturer av den här typen:

Klassen MainApi exponeras korrekt eftersom den utgör modulens API. ApiImpl är en hjälpklass till MainApi som inte skall exponeras, så den är package private. Paketet com.foo.api.util är konceptuellt ett ”underpaket” till com.foo.api. Underpaketet innehåller en delmängd av den kod som utgör huvudpaketet, men det känns bra att gruppera klasserna på något sätt. Här har vi dock ett problem! För att klasserna i com.foo.api skall komma åt hjälpklassen i underpaketet så måste den vara public

Dessvärre har Java i dagsläget inte stöd för ”underpaket”. Således har vi exponerat en klass som egentligen är en del av vår moduls inre angelägenheter för omvärlden. Hur löser man då detta? Jo:

  • Börja med att konstatera att även paket, inte bara klasser exponerar ett API.
  • Lägg saker som hör ihop i ett paket. Det finns inga underpaket i Java!
  • Kom i håg att så fort du gör en klass public så blir den del av paketets API, och utvecklaren blir för evigt styrd av den klientkod som väljer att använda klassen.