Smartare Java-utveckling

Ett snabbt och enkelt schema för att påskynda utvecklingen av storskaliga Java-applikationer innebär användning av gränssnitt. Java-gränssnitt är en ritning för funktionaliteten i ett associerat objekt.

Genom att integrera gränssnitt i ditt nästa projekt kommer du att märka fördelar under hela utvecklingsinsatsens livscykel. Tekniken för kodning till gränssnitt snarare än objekt kommer att förbättra effektiviteten i utvecklingsteamet genom att:

  • Tillåter utvecklingsteamet att snabbt etablera interaktioner mellan de nödvändiga objekten, utan att tvinga den tidiga definitionen av stödobjekten
  • Gör det möjligt för utvecklare att koncentrera sig på sina utvecklingsuppgifter med vetskapen om att integrering redan har beaktats
  • Tillhandahåller flexibilitet så att nya implementeringar av gränssnitten kan läggas till i det befintliga systemet utan större kodändringar
  • Tillämpa de avtal som överenskommits av medlemmar i utvecklingsteamet för att säkerställa att alla objekt samverkar enligt plan

En översikt

Eftersom objektorienterade utvecklingsinsatser involverar interaktioner mellan objekt är det viktigt att utveckla och genomdriva starka kontrakt mellan dessa objekt. Tekniken för kodning till gränssnitt innebär att man använder gränssnitt snarare än objekt som den primära kommunikationsmetoden.

Denna artikel kommer att introducera användaren till begreppet kodning till gränssnitt genom ett enkelt exempel. Ett detaljerat exempel kommer att följa, vilket hjälper till att visa värdet av detta schema i ett större system som kräver flera utvecklare. Innan vi kommer till exempelkoden, låt oss dock titta på fördelarna med kodning till gränssnitt.

Varför kod till gränssnitt?

Java-gränssnittet är ett utvecklingsavtal. Det säkerställer att ett visst objekt uppfyller en given uppsättning metoder. Gränssnitt används i hela Java API för att specificera nödvändig funktionalitet för objektinteraktion. Exempel på gränssnittsanvändning är återuppringningsmekanismer ( Event Listeners), mönster ( Observer) och specifikationer ( Runnable, Serializable).

Kodning till gränssnitt är en teknik genom vilken utvecklare kan exponera vissa metoder för ett objekt för andra objekt i systemet. Utvecklarna som får implementeringar av dessa gränssnitt har förmågan att koda till gränssnittet istället för kodning till själva objektet. Med andra ord skulle utvecklarna skriva kod som inte interagerade direkt med ett objekt som sådant, utan snarare med implementeringen av objektets gränssnitt.

En annan anledning att koda till gränssnitt snarare än till objekt är att det ger högre effektivitet i de olika faserna i ett systems livscykel:

  • Design : Metoderna för ett objekt kan snabbt specificeras och publiceras för alla berörda utvecklare
  • Utveckling : Java-kompilatorn garanterar att alla metoder i gränssnittet implementeras med rätt signatur och att alla ändringar i gränssnittet omedelbart är synliga för andra utvecklare
  • Integration : det finns möjligheten att snabbt ansluta klasser eller delsystem på grund av deras väletablerade gränssnitt
  • Testning : gränssnitt hjälper till att isolera buggar eftersom de begränsar omfattningen av ett möjligt logikfel till en viss delmängd av metoder

Det finns vissa omkostnader associerade med denna utvecklingsteknik på grund av den nödvändiga kodinfrastrukturen. Denna infrastruktur innehåller både gränssnitt för interaktioner mellan objekt och anropskod för att skapa implementeringar av gränssnitt. Denna overhead är obetydlig jämfört med hur enkelt och fördelar det är att använda gränssnitt enligt beskrivningen.

Grundläggande exempel

För att ytterligare förklara begreppet kodning till gränssnitt har jag skapat ett enkelt exempel. Även om detta exempel är klart trivialt, visar det några av fördelarna som nämns ovan.

Tänk på det enkla exemplet på en klass Carsom implementerar gränssnitt Vehicle. Interface Vehiclehar en enda metod som kallas start(). Class Carimplementerar gränssnittet genom att tillhandahålla en start()metod. Andra funktioner i Carklassen har utelämnats för tydlighetens skull.

gränssnitt Fordon {// Alla fordonsimplementeringar måste implementera startmetoden public void start (); } klassbil implementerar fordon {// Krävs för att implementera fordonets ogiltiga start () {...}}

Efter att ha lagt grunden till Carobjektet kan vi skapa ett annat objekt som heter Valet. Det är Valetjobbet att starta Caroch ta det till restaurangens beskyddare. Det Valetobjekt kan skrivas utan gränssnitt, enligt följande:

klass Betjänad {public Car getCar (Car c) {...}} 

Det Valetobjekt har en metod som kallas getCarsom returnerar en Carobjekt. Detta kodexempel uppfyller systemets funktionella krav, men länkar för alltid Valetobjektet med det Car. I denna situation sägs de två objekten vara tätt kopplade. Det Valetföremål kräver kunskap om Carobjektet och har tillgång till alla offentliga metoder och variabler som finns i objektet. Det är bäst att undvika en sådan tät koppling av kod eftersom det ökar beroendet och minskar flexibiliteten.

För att koda Valetobjektet med gränssnitt kan följande implementering användas:

klass Betjänad {public Vehicle getVehicle (Vehicle c) {...}} 

Medan kodändringarna är ganska små - att ändra referenserna från Cartill Vehicle- är effekterna på utvecklingscykeln betydande. Med den andra implementeringen har den Valetkunskap om de metoder och variabler som definierats i Vehiclegränssnittet. Alla andra offentliga metoder och data som ingår i den specifika implementeringen av Vehiclegränssnittet är dolda för Vehicleobjektets användare .

Denna enkla kodändring har säkerställt korrekt döljande av information och implementering från andra objekt och har därför eliminerat möjligheten att utvecklare kommer att använda oönskade metoder.

Skapa gränssnittsobjektet

Den sista frågan att diskutera med avseende på denna utvecklingsteknik är skapandet av gränssnittsobjekten. Även om det är möjligt att skapa en ny instans av en klass med newoperatören är det inte möjligt att direkt skapa en instans av ett gränssnitt. För att skapa en gränssnittsimplementering måste du starta objektet och kasta det till önskat gränssnitt. Därför kan utvecklaren som äger objektkoden vara ansvarig för att både skapa förekomsten av objektet och utföra gjutningen.

Denna skapande process kan uppnås med hjälp av ett Factorymönster där ett externt objekt anropar en statisk createXYZ()metod på a Factoryoch returnerar ett gränssnitt. Det kan också uppnås om en utvecklare anropar en metod för ett annat objekt och skickar det till ett gränssnitt istället för den faktiska klassen. Detta skulle vara analogt med att skicka ett Enumerationgränssnitt istället för ett Vectoreller Hashtable.

Detaljerat exempel

För att demonstrera användningen av detta schema i ett större projekt har jag skapat ett exempel på en mötesplanerare. Denna schemaläggare har tre huvudkomponenter: resurserna (konferensrum och mötesdeltagare), förekomsten (själva mötet) och schemaläggaren (den som underhåller resurskalendern).

Låt oss anta att dessa tre komponenter skulle utvecklas av tre olika utvecklare. Målet för varje utvecklare bör vara att fastställa användningen av hans eller hennes komponent och publicera den för de andra utvecklarna på projektet.

Tänk på exemplet med a Person. A Personkan implementera många metoder men kommer att implementera Resourcegränssnittet för denna applikation. Jag har skapat Resourcegränssnittet med alla nödvändiga accessormetoder för alla resurser som används i detta exempel (visas nedan):

offentligt gränssnitt Resurs {public String getID (); public String getName (); public void addOccurrence (Förekomst o); }

Vid denna tidpunkt har utvecklaren av Personfunktionaliteten publicerat gränssnittet genom vilket alla användare kan komma åt informationen som är lagrad i Personobjektet. Kodning till gränssnittet hjälper till att säkerställa att inga utvecklare använder Personobjektet på ett felaktigt sätt. Utvecklaren av Schedulerobjektet kan nu använda metoderna i Resourcegränssnittet för att få tillgång till den information och funktionalitet som krävs för att skapa och underhålla Personobjektets schema .

Den OccurrenceGränssnittet innehåller metoder som är nödvändiga för planering av en Occurrence. Detta kan vara en konferens, reseplan eller något annat schemaläggningshändelse. Den OccurrenceGränssnittet visas nedan:

offentligt gränssnitt Förekomst {public void setEndDatetime (Date d); public Date getEndDatetime (); public void setStartDatetime (Date d); public Date getStartDatetime (); public void setDescription (Strängbeskrivning); public String getDescription (); public void addResource (Resource r); public Resource [] getResources (); offentlig boolean förekommer På (Datum d); }

Den Schedulerkod använder Resourcegränssnittet och Occurrencegränssnittet för att upprätthålla schemat för en resurs. Observera att den Schedulerinte har någon kunskap om den enhet för vilken den håller schemat:

public class Scheduler implement Schedule {Vector schema = null; public Scheduler () {schema = ny vektor (); } public void addOccurrence (Förekomst o) {schema.addElement (o); } offentligt ogiltigt removeOccurrence (Förekomst o) {schema.removeElement (o); } public Occurrence getOccurrence (Date d) {Enumeration scheduleElements = schedule.elements (); Förekomst o = null; medan (schemaElements.hasMoreElements ()) {o = (Förekomst) schemaElements.nextElement (); // För detta enkla exempel matchar förekomsten om // datatiden är mötets starttid. Denna logik // kan göras mer komplex efter behov. if (o.getStartDatetime () == d) {break; }} returnera o; }}

Detta exempel visar kraften hos gränssnitt i utvecklingsfaserna i ett system. Var och en av delsystemen har kunskap om gränssnittet genom vilket den måste kommunicera - ingen kunskap om implementeringen krävs. Om var och en av byggstenarna i exemplet ovan skulle utvecklas vidare av team av utvecklare skulle deras ansträngningar förenklas på grund av genomförandet av dessa gränssnittskontrakt.

Slutliga tankar om gränssnitt

Den här artikeln har visat några av fördelarna med kodning till gränssnitt. Denna teknik möjliggör större effektivitet under varje fas av utvecklingslivscykeln.

During the design phases of the project, interfaces allow the quick establishment of the desired interactions among objects. The implementation objects associated with a given interface can be defined after the methods and requirements for that interface are specified. The more quickly the interaction is established, the more quickly the design phase can progress into development.

Interfaces give developers the ability to expose and limit certain methods and information to the users of their objects without changing the permissions and internal structure of the object itself. The use of interfaces can help eliminate the pesky bugs that appear when code developed by multiple development teams is integrated.

Contract enforcement is provided by the interface. Because the interface is generally agreed upon during the design phase of the project, the developers have the ability to concentrate on their individual modules without having to worry about the modules of their colleagues. Integrating these subsystems is made more efficient by the fact that the contracts have already been enforced throughout the development phase.

For testing purposes, a simple driver object can be created to implement the agreed-upon interfaces. Using this object, developers can continue their work with the knowledge that they are using the proper methods to access the object. When the objects are deployed in a test environment, the driver classes are replaced by the true classes, allowing the object to be tested without code or property changes.

This scheme provides the capability for easy expansion of this system; in our example, we could expand the code to include more forms of resources, such as meeting rooms and audio/video equipment. Any additional implementation of the Resource interface will fit into the established mechanism without modifying the existing code. Large-scale projects using this scheme could be designed and implemented in such a way that additional functionality can be added without major modification to the infrastructure. As an example, the ConferenceRoom object was created. This object implements the Resource interface and can interact with the Schedule and Occurrence implementers without changing the infrastructure.

En annan fördel är kodens centraliserade plats. Om nya metoder ska läggas till Resourcegränssnittet identifieras alla implementeringar av detta gränssnitt som kräver ändring. Detta minskar den undersökning som krävs för att fastställa den möjliga effekten av ändringar i gränssnittet.

Förutom utvecklingsfördelarna ger tekniken som presenteras i den här artikeln projektledning med försäkran om att interobjekt- eller intersystemkommunikationsmönster har etablerats och genomförts under hela utvecklingscykeln. Detta minskar risken för misslyckanden under integrations- och testfaserna i projektet.