0% found this document useful (0 votes)
71 views

Isd Assignment

The document discusses the SOLID principles of object-oriented design, which are a set of five design principles introduced by Robert C. Martin to help developers create more maintainable and flexible software. It provides an overview of each principle - Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion - and explains their importance for creating robust, understandable code that is easier to maintain and change over time. It also summarizes how following SOLID helps improve software maintainability, testability, flexibility, quality, and team collaboration.

Uploaded by

islam2059
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
0% found this document useful (0 votes)
71 views

Isd Assignment

The document discusses the SOLID principles of object-oriented design, which are a set of five design principles introduced by Robert C. Martin to help developers create more maintainable and flexible software. It provides an overview of each principle - Single Responsibility, Open/Closed, Liskov Substitution, Interface Segregation, and Dependency Inversion - and explains their importance for creating robust, understandable code that is easier to maintain and change over time. It also summarizes how following SOLID helps improve software maintainability, testability, flexibility, quality, and team collaboration.

Uploaded by

islam2059
Copyright
© © All Rights Reserved
We take content rights seriously. If you suspect this is your content, claim it here.
Available Formats
Download as PDF, TXT or read online on Scribd
You are on page 1/ 21

CSE 325

IntroDuction to Solid Programming Principles


1505048
Contents of the Doc file:

1. Introduction done by 1505048

2. Single Responsibility Principle(SRP) done by 1805081

3. Open Close Principle(OCP) done by 1805114

4. Liskov Substitution Principle done by(1805070)

5. Interface Segregation Principle &

Dependency Inversion Principle done by (1805084)

2
Introduction

The SOLID principles are a set of five design principles that were introduced by Robert C.

Martin (also known as "Uncle Bob") to help developers create more maintainable, flexible,

and scalable software. These principles provide guidelines for writing clean, modular, and

extensible code that is easier to understand, test, and maintain. By following the SOLID

principles, developers can create software that is more robust, less error-prone, and easier

to change over time. In this way, the SOLID principles have become an important aspect of

modern software development, and are widely used in a variety of programming languages

and development environments.

What are the principles?


1. Single Responsibility Principle (SRP): A class should have only one reason to change.
This principle states that a class or module should have only one reason to change,

which means that it should only have one responsibility. This helps to keep the

codebase clean and easy to maintain.

2. Open/Closed Principle (OCP): Software entities should be open for extension but
closed for modification. This principle states that classes or modules should be

designed in a way that allows them to be extended without modifying their source

code. This helps to minimize the impact of changes to the codebase.

3. Liskov Substitution Principle (LSP): Objects of a superclass should be able to be


replaced with objects of a subclass without affecting the correctness of the

program. This principle states that any subclass should be able to be used in place

of its superclass without causing any unexpected behavior or breaking the code.

4. Interface Segregation Principle (ISP): A client should not be forced to depend on


methods it does not use. This principle states that interfaces should be designed to

3
be as small and specific as possible, to prevent clients from being forced to depend

on methods they do not need.

5. 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. This principle states that

modules should depend on abstractions rather than on concrete implementations,

which helps to decouple modules and make them more flexible and reusable.

Together, these five principles form the acronym SOLID, and they provide guidelines for

designing software that is flexible, maintainable, and easy to extend.

Importance of Solid Principles

The SOLID principles are important because they provide a set of guidelines for
designing software that is easy to maintain, understand, and extend. By following these
principles, developers can create code that is more modular, less tightly coupled, and
easier to change.

Here are some specific reasons why the SOLID principles are important:

1. Maintainability: By following the Single Responsibility Principle, code is easier to


maintain because changes only affect one specific area of the codebase. This makes

it easier to isolate and fix bugs, and it also makes it easier to add new features or

modify existing ones.

2. Testability: SOLID principles can make code easier to test because they encourage
code that is more modular and loosely coupled. This allows for easier unit testing of

individual components, which can help catch bugs earlier in the development

process.

4
3. Flexibility: The SOLID principles encourage code that is flexible and extensible, which
means it can adapt to changing requirements and business needs. This can reduce

the cost and effort required to make changes to the codebase over time.

4. Code Quality: Following SOLID principles can result in code that is cleaner, more
readable, and easier to understand. This can improve the overall quality of the

codebase, making it easier to maintain and reduce the risk of introducing bugs or

errors.

5. Team Collaboration: SOLID principles provide a common language and set of


guidelines for developers to follow. This can improve communication and

collaboration among team members, making it easier to work together on complex

projects.

Overall, the SOLID principles provide guidelines for designing software that is maintainable,

extensible, and easy to understand. By following these principles, developers can create

code that is more modular, less tightly coupled, and easier to change over time

5
SRP(Single-responsibility Principle):
A class should have one and only one reason to change, meaning that a
class should have only one job. That is, if we want to change a class in
case of SRP, we should change it for one specific reason.
Now, let us take a look at the following code:

public class Filestore{


public Filestore(string workingDirectory);
public string WorkingDirectory {get;};
public void Save(int id,String message);
public Maybe<String> Read(int id);
public string GetfileName(int id);
}

public void Save(int id,String message){


Log.Information("Saving message {id}.",id);
var file=this.getFileInfo(id);
File.WriteAllText(file.FullName,message);
this.cache.AddOrUpdate(id,message,(i,s)=>message);
Log.Information("Saved message {id}.",id);
}

public Maybe<String> Read(int id){


Log.Debug("Reading message {id}.",id);
var file=this.GetFileInfo(id);
if(!file.Exists){
Log.Debug("No message {id} found.",id);
return new Maybe<String>();
}
var
message=this.cache.GetOrAdd(id,_=>File.ReadAllText(file.FullName));
Log.Debug("Returning Message {id}.",id);
return new Maybe<String>(message);
}
In the above code, the Filestore class has three different purpose, they
are: Logging, Caching and Storage. Now, if some changes occur in the
logging ar caching library or if we want to bring some changes in the
implementation of logging or caching, we must have to bring some
changes in the Filestore class. As a result, we can see that the Filestore
class can be chnaged for multiple purposes and it has multiple
responsibility instead of single responsibility. So to maintain the single-
responsibility principle we can change the above code in the following
way:
public class StoreLogger{
public void Saving(int id){
Log.Information("Saving message {id}.",id);
}
public void Saved(int id){
Log.Information("Saved message {id}.",id);
}
public void Reading(int id){
Log.Debug("Reading message {id}.",id);
}
public void DidNotFind(int id){
Log.Debug("No message {id} found.",id);
}
public void Returning(int id){
Log.Debug("Returning message {id}.",id);
}
}

public class StoreCache{


private readonly ConcurrentDictionary<int,String> cache;

public StoreCache(){
this.cache=new ConcurrentDictionary<int,String>();
}
public void addOrUpdate(int id,String message){
this.cache.AddOrUpdate(id,message,(i,s)=>message);
}
public String GetOrAdd(int id,Func<int,String> messageFactory){
return this.cache.GetOrAdd(id,messageFactory);
}
}

public class FileStore{


public void WriteAllText(String path,String message){
File.writeAllText(path,message);
}
public String ReadAllText(String path){
return File.ReadAllText(path);
}
public FileInfo GetFileInfo(int id,String workingDirectory){
return new
FileInfo(Path.Combine(workingDirectory,id+".txt"));
}
}

public class MessageStore{


private readonly StoreCache cache;
private readonly StoreLogger log;
private readonly storeFile fileStore;

public FileStore(DirectoryInfo workingDirectory){


this.cache=new StoreCache();
this.log=new Storelogger();
this.fileStore=new FileStore();
}

public void Save(int id,String message){


this.log.Saving(id);
var file=this.getFileInfo(id);
this.fileStore.WriteAllText(file.FullName,message);
this.cache.AddOrUpdate(id,message);
this.log.Saved(id);
}
public Maybe<String> Read(int id){
this.log.Reading(id);
var file=this.FileStore.GetFileInfo(id);
if(!file.Exists){
this.log.DidNotFind(id);
return new Maybe<String>();
}
var
message=this.cache.GetOrAdd(id,_=>File.ReadAllText(file.FullName));
this.log.Returning(id);
return new Maybe<String>(message);
}
}
Here, we formed different classes for Logging, Caching and also for file
management. So, if we want to bring some change in logging and caching
then we just need to change the StoreLogger and StoreCache class
separately , side by side if some changes occur in case of file management
then we should only change the Filestore class. Now, we can see that each
class serves only one specific purpose and they need to change for one
reason only. Thus the Single-responsibility principle is maintained.
It helps to reduce the improvement of a huge code easier and less
compelx.

OCP(Open-Closed Principle):
Objects or entities should be open for extension but closed for
modification. In OCP, if we want to change the behaviour of a method of a
class then we should not modify the existing code as it can still be in use
by the client code, rather we should extend the class and do the
necessary modification in the new extended class. This extension can be
done by using Inheritance or by using Composition.
Now, if we want to use Database instead of File in the previous example
code then we can change the code in the following way if we want to
follow the open-closed principle:
Extension Using Inheritance
public class FileMessageStore{
private readonly StoreCache cache;
private readonly StoreLogger log;
private readonly storeFile fileStore;
public FileStore(DirectoryInfo workingDirectory){
// code
this.fileStore=getStore();
}

public getStore(){
return new FileSore();
}

public void Save(int id,String message){


// code
}

public Maybe<String> Read(int id){


// code
}
}

public class DBMessageStore extends FileMessageStore{


@override
public getStore(){
return new DBSore();
}
}

Here, we have created a class named DBMessageStore which extends


FileMessageStore to change it from a file storage method to a database
storage method.
Extension Using Composition
public interfae IStore{
public void ReadAllText();
public void WriteAllText();
public void getFileInfo();
}

public void fileStore implements IStore{


public void ReadAllText(){
// code

public void WriteAllText(){


// code
}
public void getFileInfo(){
// code
}
}

public void DBStore implements IStore{


public void ReadAllText(){
// code
}
public void WriteAllText(){
// code
}
public void getFileInfo(){
// code
}
}

public class MessageStore{


private readonly StoreCache cache;
private readonly StoreLogger log;
private readonly IStore istore;

public FileStore(DirectoryInfo workingDirectory){


// code
this.istore=new FileStore();
}

public getStore(){
return new FileSore();
}

public void Save(int id,String message){


// code
}

public Maybe<String> Read(int id){


// code
}
}
Here, we have created an interface named IStore which implements the
Filestore and DBStore and by creating an instance of IStore in
MessageStore we can implement the required modified code without
modifying the existing code and thus it maintains the open-closed
principle.
In case of extension, Composition is more favourable than using Inher-
itance as it is more flexible.

Liskov Substitution Principle


The LSP states that objects of a superclass should be able to be replaced
with objects of a subclass without affecting the correctness of the pro-
gram.

In other words, any instance of a subclass should be able to be used in


place of an instance of its superclass, and the behavior of the program
should not change as a result. This principle is important for ensuring
that the program is robust, maintainable, and extensible.

public class FileStore


{
public virtual void WriteAllText(string path, string message)
{
File.WriteAllText(path, message);
}

public virtual string ReadAllText(string path)


{
return File.ReadAllText(path);
}

public virtual FileInfo GetFileInfo(int id, string workingDirectory)


{
return new FileInfo(
Path.Combine(workingDirectory, id + ".txt"));
}
}

If we want to create DB store, we can write logics like reading from the
database in the ReadAllText method and we can write logics like writing
to the database in the WriteAllText method. But we will not be able to
implement the GetFileInfo method in the DB store. This method is totally
irrelevant while creating a DB store. So, the "messageShow" will not
work as it requires the method for file information. actually, all these
three methods are essential for making the "messageShow" work. Now,
if we discard the GetFileInfo method, the DB store may work fine but the
FileStore will get a compilation error due to the absence of this method.
On the contrary, if we keep this method, we have to keep this method
empty or we have to return null providing some codes for checking that
whether the method is returning null or not. So, clearly there arises a
problem and we are unable to manage this situation meaningfully. Now
that, this is the claim of the Liskov Substitution Principle that there
should be no problem while the objects of a superclass is replaced with
the objects of its subclasses. In our case, the messageStore is working if
we send FileStore through the IStore, but it will not work, if we send the
DB store through the Istore. So, our instance is violating the Liskov Sub-
stitution Principle. In this condition, we have to solve for the I of SOLID.

In the following example, The function getFileInfo() of fileStore is not im-


plementable for DB store class.So, FileSore is not properly replaceable by
DB store. Thus the above example violates Liskov Substitution Principle.
Dependency Inversion Principle

The Dependency Principle states that high-level modules should not depend on low-
level modules. Instead, both should depend on abstraction. This means that the
design of a system should be such that modules should depend on abstract interfaces,
rather than concrete implementation. This promotes flexibility, reusability and
maintainability of the code.

In the above example, High Level Modules ‘MessageStore’ depends on Low Level
Modules ‘FileStore’. So, this violates Dependency Inversion Principle.
To refactor this code, we will create an interface named ‘IStore’ and inject it to the
‘MessageStore’.

Refactored Code
Now, both ‘MessageStore’ and ‘FileStore’ depends on interface ‘IStore’ but there is
no direct dependency between them.
Interface Segregation Principle

The Interface Segregation Principle states that clients should not be forced to depend
on interfaces they do not use. Instead, a class should be designed with multiple
interfaces that are specific to the client’s need. In other words, a class should not
have a single, monolithic interface that contains methods that may not be relevant to
all clients.

Now if we want to extend our ‘MessageStore’ for both ‘FileStore’ and ‘DBStore’,
we have to create a ‘DBStore’ class which will implement ‘IStore’ interface.

But here ‘DBStore’ is forced to implement ‘getFileInfo( )’ method which is not used
for Database functionalities.
So, the above code violates Interface Segregation Principle.
Refactored Code
We will divide the ‘IStore’ interface into two interfaces named ‘IStore’ and
‘IFileInfo’.

Now ‘FileStore’ class implements both ‘IStore’ and ‘IFileInfo’ interfaces.


But ‘DBStore’ class will implement only ‘IStore’ interface and thus ‘DBStore’
doesn’t need to implement unused method ‘getFileInfo( )’.

Now the above code maintains Interface Segregation Principle.

You might also like

pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy