Separation Of Concerns är den första principen i SOLID och
innebär att en klass bara ska göra en enda sak. I mitt exempel har vi en
PriceCalculator klass som räknar ut hur mycket det kostar att hyra en film.
Förutom att räkna ut priset kollar den vad det är för kundtyp och filmtyp.
Switch och if satsen är inte helt otydligt men det går att få klassen betydligt
tydligare. Nu har den fler ansvar och skulle man lägga till en kundtyp eller en
filmtyp till skulle koden börja likna spagettikod och vara jobbig att
underhålla.
Ett anrop till klassen ser ut såhär:
PriceCalculator priceCalculator = new PriceCalculator();
int price = priceCalculator.CalculatePrice(CustomerType.VIP, MovieType.Normal);
När CalculatePrice klassen anropas med VIP kund och Normal
film kommer den att skicka tillbaks ett pris på 20 kr för att VIP kunden får 5
kr i rabatt. Här nedanför är koden för att komma fram till det.
public enum CustomerType
{
Normal,
VIP
}
public enum MovieType
{
Normal,
Transfer
}
public class PriceCalculator
{
public int
CalculatePrice(CustomerType customerType, MovieType movieType)
{
switch (customerType)
{
case CustomerType.Normal:
if
(movieType == MovieType.Normal)
{
return 25 - 0;
}
else if (movieType ==
MovieType.Transfer)
{
return 35 - 0;
}
break;
case CustomerType.VIP:
if (movieType == MovieType.Normal)
{
return 25 - 5;
}
else if (movieType ==
MovieType.Transfer)
{
return
35 - 5;
}
break;
}
return
0;
}
}
Ett första steg för att få koden mer lättläst är att ta bort
CalculatePrice klassens ansvar för att kolla kundtyp, filmtyp och vad det ska
vara för rabatt. Vi delar upp det i två klasser. Kundtypen används bara för att
ta reda på vad det ska vara för rabatt så vi skapar en kundklass med en
property för rabatt. Filmtypen används för att bestämma vad det ska vara för
pris på filmen så vi skapar en klass filmklass som har en property för pris.
Genom att göra det här så blir det inte så mycket kvar att göra för
PriceCalculator mer än att ta priset – rabatten och returnera värdet.
Slutresultatet för PriceCalculatorklassen blir alltså:
public class PriceCalculator
{
public int
CalculatePrice(Customer customer, Movie movie)
{
return movie.Price - customer.Rebate;
}
}
Men hur ska vi göra för att på ett tydligt sätt visa att det
finns olika filmtyper som har olika pris? Ett sätt är att skapa en basklass som
heter film och har ett fast pris på 25 och sen göra en underklass som ärver den
klassen och gör en override på priset.
public class Movie
{
public virtual int Price { get { return 25; } }
}
public class TransferMovie : Movie
{
public override int Price { get { return 35; } }
}
På precis samma sätt kan vi göra med kundklassen för att
kunna sätta olika rabatt.
public class Customer
{
public virtual int Rebate { get { return 0; } }
}
public class VIPCustomer : Customer
{
public override int Rebate { get { return 5; } }
}
För att göra ett anrop för en VIP kund på en normal film nu
så skiljer det inte så mycket från tidigare. Man byter ut Enum typerna till
klasserna man skapat istället bara.
PriceCalculator priceCalculator = new PriceCalculator();
int price = priceCalculator.CalculatePrice(new VIPCustomer(),
new Movie());
Returvärdet man får kommer att vara 20 kr precis som
tidigare.
Separation Of Concerns är alltid bra att ha i bakhuvudet när
man kodar och börjar få nestlade if satser eller switchsatser. Ibland går det
att på ett smidigt sätt bryta isär det man gör och på så sätt få kod som är
lättare att underhålla och tydligare att använda.