presentation on solid design principles

Post on 15-Jul-2015

93 Views

Category:

Software

2 Downloads

Preview:

Click to see full reader

TRANSCRIPT

WRITING SOLID CODEпреразказ с елементи на разсъждение

Костадин Голев@kotsetogithub.com/kotse

SOLID CODE ДИЗАЙН ПРИНЦИПИ

• Първоначално наречени “първите пет принципа” от чичо Боб

• SOLID e акроним, съставен от първата буква на всеки принцип

• Целят да ни помогнат да пишем код, който е по-лесен за четене, поддръжка и надграждане

КОИ СА SOLID ПРИНЦИПИТЕ?

• (S)ingle Responsibility Principle

• (O)pen-Closed Principle

• (L)iskov Substitution Principle

• (I)nterface segregation Principle

• (D)ependency inversion Principle

КАК ГИ ИЗПОЛЗВАМЕ?

• Не са правила или закони

• Идеи, които ни помагат в взимане на решения

• Служат като средство да комуникираме дизайна на кода, който пишем

• Ако имаме усещането, че един код е добър или лош, често можем да намерим принцип, който да обясни това

КРУШКАТА И ВЕНТИЛАТОРА

SINGLE RESPONSIBILITY PRINCIPLE

Всеки клас/функция/променлива трябва да прави едно нещо и да го прави добре

По-просто - само една причина да се промени

class TaxiService { public void orderTaxi(String phoneNumber, String address) { if (phone.length() < 7 || phone.length() > 12 || phone.contains(BAD_CHARACTERS)) { throw new Exception("Phone number not valid!"); }

Taxi taxi = taxiPool.getTaxi(address);

smsClient.sendMessage(phoneNumber, “Taxi on the way!”); }}

class TaxiService { boolean validatePhoneNumber() { if (phone.length() < 7 || phone.length() > 12 || phone.contains(BAD_CHARACTERS)) {

return false; }

return true; }

public void orderTaxi(String phoneNumber, String address) { if (!validatePhoneNumber(phoneNumber)) { throw new Exception("Phone number not valid!"); }

Taxi taxi = taxiPool.getTaxi(address); smsClient.sendMessage(phoneNumber, “Taxi on the way!”); }}

class SMSService { boolean validatePhoneNumber() { if (phone.length() < 7 || phone.length() > 12 || phone.contains(BAD_CHARACTERS)) {

return false; }

return true; }

void sendSms(String phoneNumber, String message) { smsClient.sendMessage(phoneNumber, “Taxi on the way”); }}

class TaxiService { SMSService smsService;

public void orderTaxi(String phoneNumber, String address) { if (smsService.validatePhoneNumber(phoneNumber)) { throw new Exception("Phone number not valid!"); }

Taxi taxi = taxiPool.getTaxi(address); smsService.sendSMS(phoneNumber, “Taxi on the way!”); }}

SUMMARY

• Може би най-труден за прилагане от петте принципа

• По-четим и лесен за преизползване код

• Код в един метод се асоциира с името на метода

• Името на всеки метод се асоциира с името на класа

СТАРИЯ ТЕЛЕВИЗОР

OPEN-CLOSED PRINCIPLE

Кодът, който пишем трябва да е отворен за разширение и затворен за модификация

class PaymentService { int calculatePayment (int amount, Customer customer) { double discount = 0;

switch (customer.type()) { case SILVER : discount = 0.1; break; case GOLD : discount = 0.2; break; ... ... }

amountToPay = amount - amount*discount;

return amountToPay; }}

class Customer { double getDiscount() { return 0; }}

class SilverCustomer extends Customer { double getDiscount() { return 0.1; }}

class GoldCustomer extends Customer { double getDiscount() { return 0.2; }}

class PaymentService {

int calculatePayment (int amount, Customer customer) { double discount = customer.getDiscount();

amountToPay = amount - amount*discount;

return amountToPay; }}

SUMMARY

• Вместо да променяме код, който вече работи, надграждаме го

• Използваме наследяване за целта

• Нарушаване на принципа води до много трудна поддръжка на кода, тъй като една малка промяна в един клас води до множество промени в други

САЛАТЕНИЯ БАР

LISKOV SUBSTITUTION PRINCIPLE

Обектите в програмата могат да бъдат заменени от наследниците им без промяна в тяхното

поведение

public interface Duck { public void papa();}

public class RealDuck implements Duck { public void papa() { //papa code goes here! }}

public class ElectricDuck implements Duck { public void papa() { if (turnedOn) { //papa code goes here! } }}

Duck realDuck = new RealDuck();duck.papa(); //works!

Duck electricDuck = new ElectricDuck();duck.papa(); //does not work!

if (duck instanceof ElectricDuck) { ((ElectricDuck)duck).turnOn();}duck.papa(); //now works!

class ElectricDuck implements Duck { public void turnOn() { turnedOn = true }

public void papa() { if (!turnedOn) { turnOn(); } //papa code goes here! }}

Duck duck = new AnyKindOfDuck();duck.papa(); //just works with all Ducks now!

SUMMARY

• Ако бъде нарушен, даден обект нарушава обичайното си “поведение”

• На практика представлява допълнение към Open-Closed принципа, като ни "повелява", че не можем едновременно да надградим един модул и да променим неговото поведение

КНИГАТА С РЕЦЕПТИ

INTERFACE SEGREGATION PRINCIPLE

Не принуждавайте кода си за зависи от неща, от които няма нужда

public interface Worker { public void work(); public void getPaid();}

public class RegularWorker implements Worker { public void work() {} public void getPaid() {}}

public class Manager { Worker worker;

public void setWorker(Worker worker) { this.worker = worker; }

public manage () { worker.work(); }}

public class Robot implements Worker { public void work() {} public void getPaid() {} ???}

interface IWork { public void work();}

interface IGetPaid { public void getPaid();}

class Worker implements IWork, IGetPaid { @Override public void work() {

}

@Override public void getPaid() {

}}

class Robot implements IWork { @Override public void work() {

}}

class Manager { IWork worker;

void setWorker(IWork worker) { this.worker = worker; }

void manage() { worker.work(); }}

SUMMARY

• Да се пише код, който да е лесен за разбиране е не по-малко важно от това кода да работи

• Интерфейсите ни помагат да опишем как трябва да работи кода, който пишем

• Множество малки интерфейси е по-добре от това да имаме един голям т.нар "замърсен" интерфейс

ФАБРИКАТА В ЛОВЕЧ

DEPENDENCY INVERSION PRINCIPLE

Зависимостите в кода е добре да се основават на абстракции, а не конкретни неща

Модулите на по-високо ниво в кода не трябва да зависят от тези на по-ниско

public class Steed5 { Diesel130HPEngine engine;

public Steed5() { engine = new Diesel130HPEngine(); }

public void start() { engine.ignition(); }}

Steed5 car = new Steed5();car.start();

public class Steed5V8 { V8Engine engine;

public Steed5V8() { engine = new V8Engine(); }

public void start() { engine.ignition(); }}

public interface Engine { public void ignition();}

public class V8Engine implements Engine { public void ignition () {}}

Engine engine = new V8Engine();Steed5 car = new Steed5(engine);car.start();

public class Steed5 { Engine engine;

public Steed5(Engine engine) { this.engine = engine; }

public void start() { engine.ignition(); }}

SUMMARY

• При нарушаване на принципа поддръжката на кода се затруднява значително

• Ако един модул се променя, той не трябва да променя модулите на по-високо ниво от неговото

Благодаря за вниманието!

top related