Костадин Голев
@kotseto
github.com/kotse
WRITING SOLID CODE
преразказ с елементи на разсъждение
2.
SOLID CODE ДИЗАЙНПРИНЦИПИ
• Първоначално наречени “първите
пет принципа” от чичо Боб
• SOLID e акроним, съставен от
първата буква на всеки принцип
• Целят да ни помогнат да пишем код,
който е по-лесен за четене,
поддръжка и надграждане
КАК ГИ ИЗПОЛЗВАМЕ?
• Не са правила или закони
• Идеи, които ни помагат в взимане на решения
• Служат като средство да комуникираме дизайна на
кода, който пишем
• Ако имаме усещането, че един код е добър или лош,
често можем да намерим принцип, който да обясни
това
SINGLE RESPONSIBILITY PRINCIPLE
Всеки клас/функция/променлива трябва да прави
едно нещо и да го прави добре
По-просто - само една причина да се промени
8.
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!”);
}
}
9.
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!”);
}
}
10.
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”);
}
}
11.
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!”);
}
}
12.
SUMMARY
• Можеби най-труден за прилагане от петте
принципа
• По-четим и лесен за преизползване код
• Код в един метод се асоциира с името на метода
• Името на всеки метод се асоциира с името на
класа
SUMMARY
• Вместода променяме код, който вече работи,
надграждаме го
• Използваме наследяване за целта
• Нарушаване на принципа води до много трудна
поддръжка на кода, тъй като една малка промяна
в един клас води до множество промени в други
LISKOV SUBSTITUTION PRINCIPLE
Обектите в програмата могат да бъдат заменени
от наследниците им без промяна в тяхното
поведение
23.
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!
}
}
}
24.
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!
25.
class ElectricDuck implementsDuck {
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!
26.
SUMMARY
• Акобъде нарушен, даден обект нарушава
обичайното си “поведение”
• На практика представлява допълнение към
Open-Closed принципа, като ни "повелява", че
не можем едновременно да надградим един
модул и да променим неговото поведение
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();
}
}
31.
public class Robotimplements Worker {
public void work() {}
public void getPaid() {} ???
}
32.
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() {
}
}
SUMMARY
• Дасе пише код, който да е лесен за разбиране е
не по-малко важно от това кода да работи
• Интерфейсите ни помагат да опишем как трябва
да работи кода, който пишем
• Множество малки интерфейси е по-добре от това
да имаме един голям т.нар "замърсен" интерфейс
DEPENDENCY INVERSION PRINCIPLE
Зависимостите в кода е добре да се основават на
абстракции, а не конкретни неща
Модулите на по-високо ниво в кода не трябва да
зависят от тези на по-ниско
38.
public class Steed5{
Diesel130HPEngine engine;
public Steed5() {
engine = new Diesel130HPEngine();
}
public void start() {
engine.ignition();
}
}
Steed5 car = new Steed5();
car.start();
39.
public class Steed5V8{
V8Engine engine;
public Steed5V8() {
engine = new V8Engine();
}
public void start() {
engine.ignition();
}
}
40.
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();
41.
public class Steed5{
Engine engine;
public Steed5(Engine engine) {
this.engine = engine;
}
public void start() {
engine.ignition();
}
}
42.
SUMMARY
• Принарушаване на принципа поддръжката на
кода се затруднява значително
• Ако един модул се променя, той не трябва да
променя модулите на по-високо ниво от
неговото