01 单一职责原则 (Single Responsibility Principle, SRP)
- A class should have only one reason to change.
- 一个类应该只有一个引起它变化的原因。
SRP
#include <iostream>
using std::cout;
using std::endl;
class Rectangle{
public:
Rectangle(double w, double h)
:_width(w)
,_height(h)
{}
double area() const{
return _width*_height;
}
double getWidth(){
return _width;
}
double getHeight(){
return _height;
}
protected:
int _width;
int _height;
};
class RectangleGUI : public Rectangle{
public:
RectangleGUI(double w, double h)
:Rectangle(w,h){}
void draw() {
cout << "rectangle's" << "width:" << getWidth() << endl
<< "rectangle's" << "height:" << getHeight() << endl;
}
};
void test0(){
Rectangle rect(10,5);
cout << "area: " << rect.area() << endl;
RectangleGUI rectdraw(10,5);
rectdraw.draw();
}
int main()
{
test0();
return 0;
}
02 开放闭合原则(Open/Closed Principle, OCP)
- Software entities (classes, modules, functions, etc.) should be open for extension, but closed for modification.
- 软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
OCP
#include <iostream>
using std::cout;
using std::endl;
class Calculator{
public:
virtual ~Calculator() = default;
virtual double getResult(double a, double b) const = 0;
};
class PlusCalculator : public Calculator{
public:
double getResult(double a, double b) const override{
return a + b;
}
};
class MinusCalculator : public Calculator{
public:
double getResult(double a, double b) const override{
return a - b;
}
};
class MultiCalculator : public Calculator{
public:
double getResult(double a, double b) const override{
return a * b;
}
};
class DevideCalculator : public Calculator{
public:
double getResult(double a, double b) const override{
return a / b;
}
};
void test0(){
PlusCalculator plusCalc;
MinusCalculator minusCalc;
MultiCalculator multiCalc;
DevideCalculator devideCalc;
cout << "plus: " << plusCalc.getResult(10,5) <<endl;
cout << "minus: " << minusCalc.getResult(10,5) <<endl;
cout << "multi: " << multiCalc.getResult(10,5) <<endl;
cout << "devide: " << devideCalc.getResult(10,5) <<endl;
}
int main()
{
test0();
return 0;
}
03 里氏替换原则(Liskov Substitution Principle, LSP)
- Subtypes must be substitutable for their base types.
- 派生类必须能够替换其基类。
LSP1
LSP2
#include <iostream>
#include <string>
using std::cout;
using std::endl;
using std::string;
class User{
public:
User(string& name, float score)
:_name(name)
,_score(score)
{}
virtual void consume(float amount){
_score -= amount;
cout << _name << " consumed " << amount << endl;
cout << "remaining score is " << _score << endl;
}
protected:
string _name;
float _score;
};
class VipUser : public User{
public:
VipUser(string& name, float score, float discount)
:User(name, score)
,_discount(discount)
{}
//重命名consume 满足里氏替换原则
void vipconsume(float amount){
float discountedAmount = amount * _discount;
User::consume(discountedAmount);
cout << "VIP user: " << _name << " consumed ";
cout << discountedAmount << " with discount"<< endl << "remaining score is " << _score << endl;
}
void updateDiscount(float newDiscount){
_discount = newDiscount;
}
private:
float _discount;
};
void test0(){
string name1 = "jhon";
string name2 = "evan";
User user(name1, 100);
user.consume(20);
VipUser vipuser(name2, 100, 0.8);
vipuser.vipconsume(20);
}
int main()
{
test0();
return 0;
}
04 接口分离原则(Interface Segregation Principle, ISP)
- Clients should not be forced to depend on interfaces they do not use.
- 客户端不应该被迫依赖于它们不使用的接口。
ISP
核心思想:使用多个小的专门的接口,而不要使用一个大的总接口。
Bird类包括eat walk chirp
应该让Bird拆分成FlyingBird和Bird
FlyingBird新增fly()
这是Crow可以继承Flyingbird 而 Ostrich可以继承Bird
用CPP模拟这个原则
#include <iostream>
// 基类 Bird
class Bird {
public:
virtual ~Bird() = default;
virtual void eat() const {
std::cout << "Bird is eating." << std::endl;
}
virtual void walk() const {
std::cout << "Bird is walking." << std::endl;
}
virtual void chirp() const {
std::cout << "Bird is chirping." << std::endl;
}
};
// 派生类 FlyingBird
class FlyingBird : public Bird {
public:
virtual void fly() const {
std::cout << "FlyingBird is flying." << std::endl;
}
};
// Crow 继承 FlyingBird
class Crow : public FlyingBird {
public:
void fly() const override {
std::cout << "Crow is flying." << std::endl;
}
void chirp() const override {
std::cout << "Crow is cawing." << std::endl;
}
};
// Ostrich 继承 Bird
class Ostrich : public Bird {
public:
void walk() const override {
std::cout << "Ostrich is walking." << std::endl;
}
void chirp() const override {
std::cout << "Ostrich is grunting." << std::endl;
}
};
int main() {
Crow crow;
crow.eat();
crow.walk();
crow.chirp();
crow.fly();
std::cout << std::endl;
Ostrich ostrich;
ostrich.eat();
ostrich.walk();
ostrich.chirp();
return 0;
}
05 依赖倒置原则(Dependency Inversion Principle, DIP)
- High-level modules should not depend on low-level modules. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
- 高层模块不应该依赖于低层模块,两者都应该依赖于抽象。抽象不应该依赖于细节,细节应该依赖于抽象。
DIP
#include <iostream>
#include <string>
// 抽象类 BankWorker
class BankWorker {
public:
virtual ~BankWorker() = default;
// 纯虚函数 doBusiness
virtual void doBusiness() const = 0;
};
// SaveBusiness 类实现 doBusiness
class SaveBusiness : public BankWorker {
public:
void doBusiness() const override {
std::cout << "Performing save business." << std::endl;
}
};
// PayBusiness 类实现 doBusiness
class PayBusiness : public BankWorker {
public:
void doBusiness() const override {
std::cout << "Performing pay business." << std::endl;
}
};
// TransferBusiness 类实现 doBusiness
class TransferBusiness : public BankWorker {
public:
void doBusiness() const override {
std::cout << "Performing transfer business." << std::endl;
}
};
// 高层模块依赖于抽象类 BankWorker
void performBusiness(const BankWorker& worker) {
worker.doBusiness();
}
int main() {
SaveBusiness saveWorker;
PayBusiness payWorker;
TransferBusiness transferWorker;
performBusiness(saveWorker);
performBusiness(payWorker);
performBusiness(transferWorker);
return 0;
}
06 迪米特原则 (Law of Demeter, LoD)
-
又称为最少知道原则 (Principle of Least Knowledge)
- Each unit should have only limited knowledge about other units: only units “closely” related to the current unit.
- 每个单元应该对其他单元有最少的了解:只与当前单元“紧密”相关的单元。
LoD
楼盘买房问题,相比于直接看3处房产让买房者找中介买不同的房子
#include <iostream>
#include <string>
#include <vector>
using std::vector;
using std::cout;
using std::endl;
using std::string;
class Property{
public:
Property(const string& address)
:_address(address){}
string getAddress() const{
return _address;
}
private:
string _address;
};
class Agent{
public:
void addProperty(const Property& property){
properties.push_back(property);
}
void showProperties() const{
for(const auto& property : properties){
cout << "Property address: " << property.getAddress() << endl;
}
}
private:
vector<Property> properties;
};
class Buyer{
public:
Buyer(Agent& agent) : agent(agent){}
void viewProperties() const {
agent.showProperties();
}
private:
Agent& agent;
};
void test0(){
Agent agent;
agent.addProperty(Property("wuhan"));
agent.addProperty(Property("changsha"));
agent.addProperty(Property("shenzhen"));
Buyer buyer(agent);
buyer.viewProperties();
}
int main()
{
test0();
return 0;
}
07 组合复用原则Composition Over Inheritance Principle)
- Favor composition over inheritance as a reuse mechanism.
- 在复用时,优先使用组合而不是继承。
COIP
#include <iostream>
using std::cout;
using std::endl;
class Vehicle{
public:
virtual ~Vehicle() = default;
virtual void run() const{
cout << "Vehicle is running" << endl;
}
};
class BYD : public Vehicle{
public:
void run() const override{
cout << "BYD is running" << endl;
}
};
class TESLA : public Vehicle{
public:
void run() const override{
cout << "TESLA is running" << endl;
}
};
class GEELY : public Vehicle{
public:
void run() const override{
cout << "GEELY is running" << endl;
}
};
class Person{
public:
Person(Vehicle* vehicle)
:vehicle(vehicle)
{}
void drive() const{
if(vehicle){
vehicle->run();
}else{
cout << "No cat to drive" << endl;
}
}
private:
Vehicle* vehicle;
};
void test0(){
BYD byd;
TESLA tsla;
GEELY gl;
Person person1(&byd);
Person person2(&tsla);
Person person3(&gl);
person1.drive();
person2.drive();
person3.drive();
}
int main()
{
test0();
return 0;
}