当前位置:网站首页>Solid principle: explanation and examples
Solid principle: explanation and examples
2022-07-02 08:30:00 【J-A】
In object oriented programming ,SOLID yes 5 Abbreviation for an important design principle . First, by the famous software Masters Robert C.Martin (Bob uncle ) stay Design Principles and Design Patterns It is proposed that , later Michael Feathers use SOLID To summarize these five principles .
SOLID Principles make software design Easier to understand 、 Flexible and maintainable . As a software engineer , this 5 There are three principles we must know .
this paper , I will cover these principles , And illustrate with examples how it violates the principle , And how to correct it to meet SOLID principle .
S — Single responsibility principle
In programming , The single responsibility principle means that each module or class should have only one responsibility .
You may have heard such a proverb “ Do a thing and do it well ”, This refers to the principle of single responsibility .
In the article 《Principles of Object Oriented Design》 in ,Bob Uncle defines responsibility as “ The reason for the change ”. And think that there is one and only one reason to change the class or module .
class User
{
void CreatePost(Database db, string postMessage)
{
try
{
db.Add(postMessage);
}
catch (Exception ex)
{
db.LogError("An error occured: ", ex.ToString());
File.WriteAllText("\LocalErrors.txt", ex.ToString());
}
}
}
In the above code example , We noticed that *CreatePost()* Methods have multiple functions , Create a new message , Record the error log in the database and in the local file .
This violates the principle of single responsibility . We try to modify it as follows :
class Post
{
private ErrorLogger errorLogger = new ErrorLogger();
void CreatePost(Database db, string postMessage)
{
try
{
db.Add(postMessage);
}
catch (Exception ex)
{
errorLogger.log(ex.ToString())
}
}
}
class ErrorLogger
{
void log(string error)
{
db.LogError("An error occured: ", error);
File.WriteAllText("\LocalErrors.txt", error);
}
}
By abstracting the error log function , We no longer violate the principle of single responsibility .
Now there is 2 Classes , Each class has a responsibility ; Create mail and record an error log .
O — Open/closed principle
In programming , The open close principle refers to the software object ( class , modular , Function, etc. ) It should be open to extension , Turn off for changes .
If you are familiar with OOP, Then polymorphism should be no stranger . Implement through inheritance or interface , Make an abstract class have multiple subclasses , You can ensure that the code conforms to the opening and closing principle .
This sounds a little confused , So let's take an example , You'll know exactly what I'm talking about .
class Post
{
void CreatePost(Database db, string postMessage)
{
if (postMessage.StartsWith("#"))
{
db.AddAsTag(postMessage);
}
else
{
db.Add(postMessage);
}
}
}
In this code snippet , Whenever a message is written in characters “#“ start , We all need to make some assignments . However , When there are different characters beginning , Code will behave differently , This goes against the principle of opening and closing .
such as , If we want to use “@” start , We have to CreatePost() Add a ‘else if’, This modifies the class .
Inheritance is simply used here to make the code conform to the open and close principle .
class Post
{
void CreatePost(Database db, string postMessage)
{
db.Add(postMessage);
}
}
class TagPost : Post
{
override void CreatePost(Database db, string postMessage)
{
db.AddAsTag(postMessage);
}
}
By using inheritance , rewrite *CreatePost()* Method to create the extended behavior of the message .
Now? , Judge the first character “#” It can be handled elsewhere in the software . The cooler thing is , If we want to change postMessage The way to judge , Can not affect the behavior of the base class .
L — Liskov substitution principle
This principle is probably the most difficult to understand at the first introduction .
In programming , The Richter substitution principle refers to if S yes T Subclasses of , that T Examples of can be used S Instead of .
A more general expression is , Without changing the correctness of the program , A derived class object can replace its base class object in a program .
class Post
{
void CreatePost(Database db, string postMessage)
{
db.Add(postMessage);
}
}
class TagPost : Post
{
override void CreatePost(Database db, string postMessage)
{
db.AddAsTag(postMessage);
}
}
class MentionPost : Post
{
void CreateMentionPost(Database db, string postMessage)
{
string user = postMessage.parseUser();
db.NotifyUser(user);
db.OverrideExistingMention(user, postMessage);
base.CreatePost(db, postMessage);
}
}
class PostHandler
{
private database = new Database();
void HandleNewPosts() {
List<string> newPosts = database.getUnhandledPostsMessages();
foreach (string postMessage in newPosts)
{
Post post;
if (postMessage.StartsWith("#"))
{
post = new TagPost();
}
else if (postMessage.StartsWith("@"))
{
post = new MentionPost();
}
else {
post = new Post();
}
post.CreatePost(database, postMessage);
}
}
}
Because there is no override ,CreatePost() Method in subclass MentionPost Will not play its due role .
Revised as follows :
...
class MentionPost : Post
{
override void CreatePost(Database db, string postMessage)
{
string user = postMessage.parseUser();
NotifyUser(user);
OverrideExistingMention(user, postMessage)
base.CreatePost(db, postMessage);
}
private void NotifyUser(string user)
{
db.NotifyUser(user);
}
private void OverrideExistingMention(string user, string postMessage)
{
db.OverrideExistingMention(user, postMessage);
}
}
...
By refactoring MentionPost class , Can meet the replaceability .
This is just a simple example that does not violate the Richter substitution principle . However , In actual use , This situation can be achieved in many ways and is not easy to identify .
I — Interface segregation principle
This principle is easy to understand , actually , If you are used to using interfaces , There is a high probability that this principle will be used .
In programming , The principle of interface isolation means that customers should not be forced to use methods or functions that are useless to them .
simply , Don't add new methods to existing interfaces to realize new functions . Contrary , You can create new interfaces , If necessary , You can make your class implement multiple interfaces .
interface IPost
{
void CreatePost();
}
interface IPostNew
{
void CreatePost();
void ReadPost();
}
In the above code example , Suppose I already have one IPost Interface , contain CreatePost() Method ; later , I added a new method ReadPost(), This interface has been modified , become IPostNew Interface , This violates the principle of interface isolation . Revised as follows :
interface IPostCreate
{
void CreatePost();
}
interface IPostRead
{
void ReadPost();
}
Once any class needs to implement this 2 A way , This will be achieved at the same time 2 Interface .
D - Dependency inversion principle
Last , Let's take a look D, The last design principle .
In programming , The dependency inversion principle is used to decouple modules in software . This principle is expressed as follows :
- High level modules should not rely on low-level modules , Instead, we should rely on abstraction ;
- Abstraction should not rely on implementation details , Implementation details should rely on abstraction .
In order to follow this principle , We need to use a design pattern called Dependency injection , Typical , Dependency injection takes the constructor of the class as the input parameter .
class Post
{
private ErrorLogger errorLogger = new ErrorLogger();
void CreatePost(Database db, string postMessage)
{
try
{
db.Add(postMessage);
}
catch (Exception ex)
{
errorLogger.log(ex.ToString())
}
}
}
Observe that we are Post Class ErrorLogger example , If we want to use different logs , We need to change Post class , This goes against the principle of dependence inversion . Revised as follows :
class Post
{
private Logger _logger;
public Post(Logger injectedLogger)
{
_logger = injectedLogger;
}
void CreatePost(Database db, string postMessage)
{
try
{
db.Add(postMessage);
}
catch (Exception ex)
{
_logger.log(ex.ToString());
}
}
}
By using dependency injection , We no longer rely on Post Class to define the log of the specified type .
OK, After introducing so many , I have also roughly understood these principles . These principles are different , At the same time, they are also connected .
- The principle of single responsibility is SOLID The basis of all principles and ideas for solving problems .
- The principle of opening and closing is the principle that directly guarantees the quality of code , To solve the vulnerability of design 、 Ossification 、 Difficult to read 、 Difficult to reuse , The key to applying the opening and closing principle is how “ abstract ”.
- The Richter substitution principle ensures that subclasses and superclasses are “is a” The relationship between , To help realize the opening and closing principle . The principle is in use , Extend the object-oriented perspective “is a” It's about behavior , And the correctness of the model is not inherent , It is embodied by its client program .
- The interface isolation principle provides a solution , Without violating the Richter replacement principle , How to realize the open close principle . At the same time, the idea of interface isolation also embodies the principle of single responsibility .
- Dependency inversion principle is the watershed between procedural design and object-oriented design , Through appropriate abstraction , Make high-level modules as reusable and testable as low-level modules . It's also used to guide interface isolation principles .
Reference resources
【2】Single Responsibility Principle in C++
【4】Open Closed Principle in C++
【5】 Opening and closing principle
【6】Liskov’s Substitution Principle in C++
【7】 Richter's principle of substitution
【8】Interface Segregation Principle in C++
【9】 Interface isolation principle
【10】Dependency Inversion Principle in C++
【11】 The principle of Dependence Inversion
That’s it!If you have any questions or feedback, please feel free to comment below.
-EOF-
边栏推荐
- ICMP Protocol
- [untitled]
- HCIA - application layer
- 旋转链表(图解说明)
- Use C language to receive JSON strings
- My VIM profile
- c语言自定义类型枚举,联合(枚举的巧妙使用,联合体大小的计算)
- Simple implementation scheme of transcoding and streaming (I)
- sqli-labs第2关
- What are the platforms for selling green label domain names? What is the green label domain name like?
猜你喜欢
web安全--逻辑越权
Simple implementation scheme of transcoding and streaming (I)
File upload Labs
[untitled]
使用Matplotlib绘制图表初步
Introduction to parameters of CarSim pavement 3D shape file
Don't know mock test yet? An article to familiarize you with mock
Carsim-問題Failed to start Solver: PATH_ID_OBJ(X) was set to Y; no corresponding value of XXXXX?
Use Wireshark to grab TCP three handshakes
OpenCV3 6.3 用滤波器进行缩减像素采样
随机推荐
Summary of one question per day: String article (continuously updated)
SQL operation database syntax
Carla-UE4Editor导入RoadRunner地图文件(保姆级教程)
ICMP Protocol
OpenCV常用方法出处链接(持续更新)
Matlab-其它
sqli-labs第8关(布尔盲注)
My VIM profile
The source code of the live app. When the verification method is mailbox verification, the verification code is automatically sent to the entered mailbox
Global and Chinese markets for magnetic resonance imaging (MRI) transmission 2022-2028: Research Report on technology, participants, trends, market size and share
k8s入门:Helm 构建 MySQL
Carsim-问题Failed to start Solver: PATH_ID_OBJ(X) was set to Y; no corresponding value of XXXXX?
文件上传-upload-labs
VS Code配置问题
Web security -- Logical ultra vires
高中数学必修一
C language implements XML generation and parsing library (XML extension)
Fundamentals of music theory (brief introduction)
Method recursion (Fibonacci sequence, frog jumping steps, tower of Hanoi problem)
Simple implementation scheme of transcoding and streaming (I)