Successfully reported this slideshow.
We use your LinkedIn profile and activity data to personalize ads and to show you more relevant ads. You can change your ad preferences anytime.

Presentation on SOLID design principles

433 views

Published on

Presentation in Bulgarian about SOLID design principles.

Presented at PlovDev conference and in Proxiad office in Sofia

Published in: Software
  • Be the first to comment

  • Be the first to like this

Presentation on SOLID design principles

  1. 1. Костадин Голев @kotseto github.com/kotse WRITING SOLID CODE преразказ с елементи на разсъждение
  2. 2. SOLID CODE ДИЗАЙН ПРИНЦИПИ • Първоначално наречени “първите пет принципа” от чичо Боб • SOLID e акроним, съставен от първата буква на всеки принцип • Целят да ни помогнат да пишем код, който е по-лесен за четене, поддръжка и надграждане
  3. 3. КОИ СА SOLID ПРИНЦИПИТЕ? • (S)ingle Responsibility Principle • (O)pen-Closed Principle • (L)iskov Substitution Principle • (I)nterface segregation Principle • (D)ependency inversion Principle
  4. 4. КАК ГИ ИЗПОЛЗВАМЕ? • Не са правила или закони • Идеи, които ни помагат в взимане на решения • Служат като средство да комуникираме дизайна на кода, който пишем • Ако имаме усещането, че един код е добър или лош, често можем да намерим принцип, който да обясни това
  5. 5. КРУШКАТА И ВЕНТИЛАТОРА
  6. 6. SINGLE RESPONSIBILITY PRINCIPLE Всеки клас/функция/променлива трябва да прави едно нещо и да го прави добре По-просто - само една причина да се промени
  7. 7. 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!”); } }
  8. 8. 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!”); } }
  9. 9. 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”); } }
  10. 10. 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!”); } }
  11. 11. SUMMARY • Може би най-труден за прилагане от петте принципа • По-четим и лесен за преизползване код • Код в един метод се асоциира с името на метода • Името на всеки метод се асоциира с името на класа
  12. 12. СТАРИЯ ТЕЛЕВИЗОР
  13. 13. OPEN-CLOSED PRINCIPLE Кодът, който пишем трябва да е отворен за разширение и затворен за модификация
  14. 14. 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; } }
  15. 15. class Customer { double getDiscount() { return 0; } } class SilverCustomer extends Customer { double getDiscount() { return 0.1; } } class GoldCustomer extends Customer { double getDiscount() { return 0.2; } }
  16. 16. class PaymentService { int calculatePayment (int amount, Customer customer) { double discount = customer.getDiscount(); amountToPay = amount - amount*discount; return amountToPay; } }
  17. 17. SUMMARY • Вместо да променяме код, който вече работи, надграждаме го • Използваме наследяване за целта • Нарушаване на принципа води до много трудна поддръжка на кода, тъй като една малка промяна в един клас води до множество промени в други
  18. 18. САЛАТЕНИЯ БАР
  19. 19. LISKOV SUBSTITUTION PRINCIPLE Обектите в програмата могат да бъдат заменени от наследниците им без промяна в тяхното поведение
  20. 20. 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! } } }
  21. 21. 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!
  22. 22. 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!
  23. 23. SUMMARY • Ако бъде нарушен, даден обект нарушава обичайното си “поведение” • На практика представлява допълнение към Open-Closed принципа, като ни "повелява", че не можем едновременно да надградим един модул и да променим неговото поведение
  24. 24. КНИГАТА С РЕЦЕПТИ
  25. 25. INTERFACE SEGREGATION PRINCIPLE Не принуждавайте кода си за зависи от неща, от които няма нужда
  26. 26. 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(); } }
  27. 27. public class Robot implements Worker { public void work() {} public void getPaid() {} ??? }
  28. 28. 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() { } }
  29. 29. class Manager { IWork worker; void setWorker(IWork worker) { this.worker = worker; } void manage() { worker.work(); } }
  30. 30. SUMMARY • Да се пише код, който да е лесен за разбиране е не по-малко важно от това кода да работи • Интерфейсите ни помагат да опишем как трябва да работи кода, който пишем • Множество малки интерфейси е по-добре от това да имаме един голям т.нар "замърсен" интерфейс
  31. 31. ФАБРИКАТА В ЛОВЕЧ
  32. 32. DEPENDENCY INVERSION PRINCIPLE Зависимостите в кода е добре да се основават на абстракции, а не конкретни неща Модулите на по-високо ниво в кода не трябва да зависят от тези на по-ниско
  33. 33. public class Steed5 { Diesel130HPEngine engine; public Steed5() { engine = new Diesel130HPEngine(); } public void start() { engine.ignition(); } } Steed5 car = new Steed5(); car.start();
  34. 34. public class Steed5V8 { V8Engine engine; public Steed5V8() { engine = new V8Engine(); } public void start() { engine.ignition(); } }
  35. 35. 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();
  36. 36. public class Steed5 { Engine engine; public Steed5(Engine engine) { this.engine = engine; } public void start() { engine.ignition(); } }
  37. 37. SUMMARY • При нарушаване на принципа поддръжката на кода се затруднява значително • Ако един модул се променя, той не трябва да променя модулите на по-високо ниво от неговото
  38. 38. Благодаря за вниманието!

×