måndag 16 mars 2009

Don't ask, tell

En liten utveckling på G5 som är beskriven tidigare. Mycket duplicering kan lösas genom att koda på en annan abstraktionsnivå. Genom att byta abstraktionsnivå kan dupliceringen förvinna. Låter lite småflummigt så jag skriver ner ett exempel:

public String getName(Example e){
String name;
if(e.type.equals("private customer"){
name = e.firstName + " " + e.lastName;
}else if(e.type.equals("supplier"){
name = e.companyName;
}else if(e.type.equals("creditor"){
name = e.creditName + "@" + e.companyName;
}
return name;
}

Koden ovanför är något krystad men beskriver ett objekt där "type" kan ha minst tre värden. Värdet på "type" bestämmer hur man ska bygga upp objektets name. Antag nu att den här koden är copy'n pastad på några ställen och du kommer på att name inte ska vara creditName + "@" + companyName utan i stället bara companyName. Då är risken ganska stor att man bara ändrar på första stället och lämnar en otrevlig bugg efter sig. Men hur ska man då hantera situationen? Vi ska byta plats för var man bygger namnet. I stället för att ha en Example-klass ska vi ha tre stycken subklasser till Example som var och en vet hur den skapar sitt eget namn.

public String getName(Example e){
return e.getName();
}

Vänta nu, hur gick det där till?

  1. Gör den existerande publika konstruktorn protected så att bara subklasser kan använda den. Det genererar ett gäng kompilieringsfel men det gör inget.
  2. Skapa en klass som heter ExampleFactory.
  3. Lägg till en metod createExample i ExampleFactory som tar samma argument som den nu protected konstruktorn i Examle. Implementera metoden enligt följande 4.
  4. public Example createExample(String type, .... ){
    Example example = null;
    if(e.type.equals("private customer"){
    example = new PrivateCustomer(....);
    }else if(e.type.equals("supplier"){
    example = new Supplier(....);
    }else if(e.type.equals("creditor"){
    example = new Creditor(....);
    }
    return example;
    }
  5. PrivateCustomer, Supplier och Creditor ärver samtliga från Example och samtliga implemeterar sin version av getName()
Nu har vi dolt den fula if-satsen i en factory. Det är det enda stället vi behöver den. Genom att skapa objekt på en bättre abstraktionsnivå har vi fått bort dupliceringen.

.... noteringen är för att jag är för lat för att skriva exemplet komplett.

Inga kommentarer:

Skicka en kommentar