SOLID - IsuiGit/borodaedu GitHub Wiki

Определение

SOLID - это набор пяти принципов ООП проектирования, которые помогают создавать более гибкие, поддерживаемые и масштабируемые системы.

SRP

Single responsibility principle (принцип единственности ответственности). Принцип SRP гласит о том, что у класса должна быть только одна причина для изменения, т.е. он должен иметь только одну ответственность.

//class User {
//public:
//	void setName();
//	std::string getName();
//	void print(); // <- обязует каждый объект класса User предоставлять интерфейс
//	// вывода данных о пользователе внутри себя.
//private:
//	std::string name;
//};

class User {
public:
	void setName(std::string name) { this->name = name; };
	std::string getName() { return name; };
private:
	std::string name;
};

class Interface {
public:
	static void printUser(User& user) {
		std::cout << user.getName() << std::endl;
	};
};

int main() {
	User u;
	u.setName("ORKADIY");
	Interface::printUser(u);
}

OCP

Open/Closed principle (принцип открытости/закрытости) утверждает, что классы должны быть открыты для расширения, но закрыты для модификации. Это означает, что поведение класса можно изменять, не меня его исходный код.

class Shape {
public:
	Shape() { ++count; }
	static int getCount() { return count; }
	virtual double area() const = 0; // Абстрактный метод вычисления площади
private:
	inline static int count = 0;
};

class Circle : public Shape {
public:
	Circle(double radius) : radius(radius) {}
	double area() const override {
		return 3.14 * radius * radius;
	}
private:
	double radius;
};

class Rectangle : public Shape {
public:
	Rectangle(double width, double height) :width(width), height(height) {}
	double area() const override {
		return width * height;
	}
private:
	double width, height;
};

int main() {
	Circle c(10.0);
	Rectangle r(5.0, 3.0);
	std::cout << c.area() << std::endl;
	std::cout << r.area() << std::endl;
	std::cout << Shape::getCount() << std::endl;
}

LSP

Принцип подстановки Лисков гласит, что объекты подкласса должны быть взаимозаменяемыми с объектами базового класса без изменения правильности программы.

// Пример нарушения LSP
//class Bird {
//public:
//	virtual void fly() const{ /* птица летает */ }
//};
//
//class Sparrow : public Bird {
//public:
//	void fly() const override {}
//};
//
//class Ostrich : public Bird {
//	void fly() const override {
//		throw std::runtime_error("Страусы не летают!");
//	}
//};

class Flyable { // <- отдельный класс для "летательных" объектов
	virtual void fly() const {}
};

class Walkable { // <- отдельный класс для "ходительных" объектов
	virtual void walk() const {}
};

class Sparrow : public Flyable, public Walkable { //<- наследуется от всех классов
public:
	void fly() const override {}
	void walk() const override {}
};

class Ostrich : public Walkable { // <- наследуется только от необходимых классов
public:
	void walk() const override {}
};

ISP

Interface Segregation Principle (принцип разделения интерфейса) утверждает, что клиенты не должны зависеть от интерфейсов, которые они используют. Это означает, что лучше иметь несколько специализированных интерфейсов, чем один универсальный.

// Ай как хорошо!
class Printer {
public:
	virtual void print() = 0;
};

class Scanner {
public:
	virtual void scan() = 0;
};

class MultiFucntionalPrint : public Printer, public Scanner {
public:
	void print() override {}
	void scan() override {}
};

// Очень плохо!
class MultiCoolSuperDuperPrinter2007 {
public:
	void do_smth(int type) {
		if (type == 1) {
			CosmicCoolPrint();
		}
		else if (type == 2) {
			MegaScan()
		}
		else if (type != 1 && type != 2) {
			panic!();
		}
		else {
			call_to_sysadmin();
		}
	}
};

DIP

Dependency Inversion Principle (принцип инверсии зависимостей) гласит, что высокоуровневые модули не должны зависеть от низкоуровневых, а оба должны зависеть от абстракций. Также абстракции не должны зависеть от деталей, а детали должны зависеть от абстракций.

#include <iostream>

class IMessageSender {
public:
	virtual void sendMessage(const std::string& message) = 0;
};

class EmailSender : public IMessageSender {
	void sendMessage(const std::string& message) override {}
};

class PushSender : public IMessageSender {
	void sendMessage(const std::string& message) override {}
};

class Notification {
private:
	IMessageSender& messageSender;
public:
	Notification(IMessageSender& sender) : messageSender(sender) {}
	void notify(const std::string& message) {
		messageSender.sendMessage(message);
	}
};

int main() {
	EmailSender es;
	PushSender ps;
	Notification notif(ps);
}
⚠️ **GitHub.com Fallback** ⚠️