solid principles
TRANSCRIPT
SOLID principles
What makes a good software?
Promote object orient programming and design
Promote code reuse
Prevent duplicated code
Promote adaptive software development
Keep things simple + YAGNI
Basic principles• Degree to which each program
module relies on each one of the other modules.
Coupling
• Degree to which elements belong together.Cohesion
• Make objects interchangeable, and guards their states from invalid changes
Encapsulation
Cohesion levels
WORST
• Coincidental Logical Temporal
• Procedural Communicational• Sequencial
BEST• Functional
Couplingpublic void DoSomething() { // Go get some configuration int threshold = int.Parse(ConfigurationManager.AppSettings["threshold"]);
string connectionString = ConfigurationManager.AppSettings["connectionString"];
string sql = @"select * from things size > ";
sql += threshold;
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
SqlCommand command = new SqlCommand(sql, connection); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { string name = reader["Name"].ToString(); string destination = reader["destination"].ToString();
// do some business logic in here doSomeBusinessLogic(name, destination, connection); } ….} }
Couplingpublic void DoSomething() { // Go get some configuration int threshold = int.Parse(ConfigurationManager.AppSettings["threshold"]);
string connectionString = ConfigurationManager.AppSettings["connectionString"];
string sql = @"select * from things size > ";
sql += threshold;
using (SqlConnection connection = new SqlConnection(connectionString)) {
connection.Open();
SqlCommand command = new SqlCommand(sql, connection); using (SqlDataReader reader = command.ExecuteReader()) { while (reader.Read()) { string name = reader["Name"].ToString(); string destination = reader["destination"].ToString();
// do some business logic in here doSomeBusinessLogic(name, destination, connection); } ….} }
SOLID principles
• Single responsibility principleSRP• Open/Closed principle OCP• Liskov substitution principleLSP• Interface segregation principleISP• Dependency inversion principleDIP
S - Single responsibility principle (SRP)
Object should have only a single responsibility.
Single responsibility principle
Responsibility 1:Station related
Responsibility 2:Volume related
Single responsibility principle
Responsibility 1:Station related
Responsibility 2:Volume related
O - Open/closed principle (OCP)
Object should be open for extension, but closed for modification.
Open/closed principle
Open for extension?
Closed for modification?
Open/closed principle
DrawShape in GraphicEditor{
public void DrawShape(Shape s) { if (s._type == 1) { DrawRectangle((Rectangle)s); } else if (s._type == 2) { DrawCircle((Circle)s); }}
Drawing in GraphicEditor
public void DrawRectangle(Rectangle s) { Console.WriteLine("Rectangle"); } public void DrawCircle(Circle s) { Console.WriteLine("Circle"); }}
Open/closed principle
Open for extension
Closed for modification
L - Liskov substitution principle (LSP)
Derived classes must be substitutable for their base classes.
Liskov substitution principle
Is a square rectangle?
Liskov substitution principlepublic void SetWidth(Rectangle rect, int width) { rect.Width = width; } -------------------------------Rectangle rect = new Rectangle(50, 20);
SetWidth(rect, 100);
Assert.AreEqual(20,rect.Height);
Liskov substitution principle
Is a square rectangle?
Liskov substitution principle
I - Interface segregation principle (ISP)
Clients should not be forced to implement interfaces they don’t use.
Or as Uncle Bob puts it: Make fine grained interfaces that are client specific.
Interface segregation principle
Calendar date
required for birthday?
Interface segregation principle
Calendar date
required for birthday?
D - Dependency inversion principle (DIP)
high-level classes should not depend on low-level classes. Both should depend on abstractions. Abstractions should not depend on details. Details should depend on abstractions.
Dependency inversion principlepublic class BirthdayCalculator{ private readonly List<Birthday> _birthdays; public BirthdayCalculator() { _birthdays = new List<Birthday>(); } public List<Birthday> Birthdays { get { return _birthdays; } } public List<Birthday> GetTodaysBirthdays() { return _birthdays .Where(bd => bd.Date.Month == DateTime.Now.Date.Month) .Where(bd => bd.Date.Day == DateTime.Now.Date.Day) .ToList(); }}
Dependency inversion principlepublic class BirthdayCalculator{ private readonly List<Birthday> _birthdays; public BirthdayCalculator() { _birthdays = new List<Birthday>(); } public List<Birthday> Birthdays { get { return _birthdays; } } public List<Birthday> GetTodaysBirthdays() { return _birthdays .Where(bd => bd.Date.Month == DateTime.Now.Date.Month) .Where(bd => bd.Date.Day == DateTime.Now.Date.Day) .ToList(); }}
Dependency inversion principlepublic class BirthdayCalculator{ private readonly IList<Birthday> _birthdays; public BirthdayCalculator(IList<Birthday> birthdays) { _birthdays = birthdays; } public IList<Birthday> Birthdays { get { return _birthdays; } } public IList<Birthday> GetBirthdays(DateTime checkDate) { return _birthdays .Where(bd => bd.Date.Day == checkDate.Day) .Where(bd => bd.Date.Month == checkDate.Month) .ToList(); }}
QUIZ 1/5
A class should have one, and only one, reason to change.
SRP
QUIZ 2/5
You should be able to extend a classes behavior, without modifying it.
OCP
QUIZ 3/5
References to base classes must be able to use objects of derived classes without knowing it
LSP
QUIZ 4/5
Make fine grained interfaces that are client specific.
ISP
QUIZ 5/5
Depend on abstractions, not on concretions.
DIP
Correlations
• SRP correlates with the DIP since the abstraction of responsibilities is often reached by inversion of dependecies.
• OCP correlates with the DIP since the openness for change is opften reached by inversion of dependecies.
• DIP correlates with OCP, since there is the chance that new requirements could be satisfied by adding details to existing abstractions.