SOLID_design_principle
The following two tabs change content below.
Hi, I have written and developed this site to share my experience and ideas with other colleagues. I also started to prepare interview questions and answers for job seekers. I hope it will help you a lot.
Before to start making application we need to make sure our code is well written and easy to use/maintained by other user . But to achieve all these things we should follow the best design principle like we have SOLID. SOLID design principles are given below:
For full SOLID design principles example you can download from My Repo
S: Single Responsible Principle
“One class should have one and only one responsibility”
As an example, I am taking an example of Blog. we know every blog have many posts/article. So with the help of BlogPost I am trying to explain the concept.
Wrong code:
package com.kpblogs.solid_design_principles.srp;

public class BlogPost
 {
 String text;
 String author;
 int length;

//Setter getter

/*methods that change the text*/
 void changeContentFormat() { 
 }

/*method for formatting output*/
 void printText() { 
 }
}
In the above code BlogPost class trying to change the content format and also do the content print which is wrong we need to separate these two logic into different classes like below:
package com.kpblogs.solid_design_principles.srp;

public class BlogPost
 {
  private String text;
  private String author;
  private int length;
  //Setter getter

  /*methods that change the text format */
   void changeContentFormat() { 
    }
}


//Created separate class for content print

class PrintContent{
 private BlogPost post;
 public PrintContent(BlogPost post) {
 this.post = post;
}

 private String doContentPrint(){
   return "In this method will start the content printing process";
 }

}
The reason it is important to keep a class focused on a single concern is that it makes the class more robust. Continuing with the foregoing example, if there is a change to the content format, there is greater danger that the printing code will break if it is part of the same class.
O: Open Closed Principle
“Software component should be open for extention, but closed for modification.”
Open for extension : This means that the behavior of a software module, say a class can be extended to make it behave in new and different ways. It is important to note here that the term “extended ” is not limited to inheritance using the Java extend keyword. As mentioned earlier, Java did not exist at that time. What it means here is that a module should provide extension points to alter its behavior. One way is to make use of polymorphism to invoke extended behaviors of an object at run time.
Closed for modification : This means that the source code of such a module remains unchanged.
Consider an File Viewer that will open the file in particuler mode like pdf, png, jpg etc. We can follow the complementary Single Responsibility Principle (On top of this page) to model this requirement by creating two separate classes. A ViewerType class responsible to set View type mode and a FileViewer class is responsible to open file into the given viewer mode.
Wrong Code
package com.kpblogs.solid_design_principles.ocp;
public class FileViewer {

 public void openingFileViewer(ViewType pdf){
   pdf.openFileInPDF();
 }
}

class ViewType{
 public void openFileInPDF(){
  System.out.println("File opening ..as..PDF");
 }
}
In the above code if we are trying to open PNG file then we need to add update FileViewer class which is the  violation of the Open Closed Principle. So to avoid this we can use below code:
Created Interface ViewType.java for loose coupling
package com.kpblogs.solid_design_principles.ocp;
public interface ViewType {
  public void openFile();
}
Created different viewer according to requirement. and now if we want to add more viewer then just create new class and extend ViewType like below PDFViewer.java:
package com.kpblogs.solid_design_principles.ocp;
public class PDFViewer implements ViewType{

public void openFile() {

    System.out.println("Opening PDF file...");

}
}
Now pass the ViewType interface to FileViewer. in this way if we are adding new type of Viewer we no need to change code of FileViewer just use below code:
package com.kpblogs.solid_design_principles.ocp;
public class FileViewer {
  public void openingFileViewer(ViewType type){
    type.openFile();
  }
}
L: Liskov’s Substitution Principle
“Derived types must be completely substitutable for their base types.”
The Liskov substitution principle (LSP) is a collection of guidelines for creating inheritance hierarchies in which a client can reliably use any class or subclass without compromising the expected behavior. Here is the official definition:
If S is a subtype of T, then objects of type T may be replaced with objects of type S, without breaking the program.
—Barbara Liskov
 Tu under stand it more correctly taking an example of Phone which have some common features like below:
package com.kpblogs.solid_design_principles.lsp;

public class Phone {
private String number;

void dialingNumber(){
  System.out.println("Dialing Number..");
}

void ringing(){
 System.out.println("Phone Ringing .. ");
}

boolean isRangeAvailable(){
  return true;
}
}

class LandLinePhone extends Phone{

@Override
void dialingNumber() {
// TODO Auto-generated method stub
   super.dialingNumber();
}

@Override
void ringing() {
// TODO Auto-generated method stub
super.ringing();
}

}

Everything isn’t going as planned now! Yes, a LandLinePhone is a communication device, however, it does not need to check range and hence, the method isRangeAvailable() cannot be implemented.

These are the kinds of problems that violation of Liskov Substitution Principle leads to, and they can most usually be recognized by a method that does nothing, or even can’t be implemented.

 

The solution to these problems is a correct inheritance hierarchy, and in our case we would solve the problem by differentiating classes of Phone devices with and without Range. Real Implementation is given below:

Created another two classes one for Landline and one for Wireless phone and they are using common feature of Phone class. as given below:

package com.kpblogs.solid_design_principles.lsp;
public class LandlinePhone extends Phone {
@Override

void dialingNumber() {
// TODO Auto-generated method stub
super.dialingNumber();
}
 

@Override
void ringing() {
// TODO Auto-generated method stub
super.ringing();
}
}

 

In WirelessPhone added new feature isRangeAvailable() to check range as given below:

package com.kpblogs.solid_design_principles.lsp;
public class WireLessPhone extends Phone{

//added new feature
boolean isRangeAvailable() {
   return true;
} 

@Override
void ringing() {
// TODO Auto-generated method stub
super.ringing();
}

@Override
void dialingNumber() {
// TODO Auto-generated method stub
super.dialingNumber();
}
}

 

I: Interface Segregation Principle

“Clients should not be forced to implement unnecessary methods which they will not use”
Like – Splits interfaces that are very large into smaller and more specific ones so that clients will only have to know about the methods that are of interest to them.
For example prospective we take same example which we mention in  Liskov’s Substitution Principle. Just small change if we are using Interface rather then class for Phone, LandLinePhone, WirelessPhone as given below:
package com.kpblogs.solid_design_principles.isp;
interface Phone{
  void dialingNumber();

  void ringing();

  boolean isRangeAvailable();
}

class LandLinePhone implements Phone{

 public void dialingNumber() {

 // TODO Auto-generated method stub
}

public void ringing() {
// TODO Auto-generated method stub
}

public boolean isRangeAvailable() {
// TODO Auto-generated method stub
return false;
}
}

}
 As you can see in the code, LandLinePhone needs to provide implementation of isRangeAvailable() method, even though it does not require. This is a violation of the Interface Segregation Principle. Such violations affect code readability and confuse programmers.
 Violation of the Interface Segregation Principle also leads to violation of the complementary Open Closed Principle (Given above) . As an example, consider that the Phone interface is modified to include a checkWire() method to accommodate LandLinePhone.
The solution is- Segregate the Phone interface into multiple role interfaces each for a specific behavior. Let’s segregate the Phone interface, so that our application now have three interfaces: Phone, WiredPhone, and WireLessPhone.
interface Phone{
    void dialingNumber();
    void ringing();
}

interface WiredPhone extends Phone{
   boolean isWireOk();
}


interface WireLessPhone extends Phone{
   boolean isRangeAvailable();
}
Once we need implement then we can use appropriate interface as given below :
/**
 * 
 *Now if we are working with Wireless device then implement WirelessPhone Interface else for Wired us
 *WiredPhone interface
 *
 */
class Mobile implements WireLessPhone{

public void dialingNumber() {
// TODO Auto-generated method stub
}

public void ringing() {
// TODO Auto-generated method stub
}

public boolean isRangeAvailable() {
// TODO Auto-generated method stub
return false;
}
}
D: Dependency Inversion Principle
“Depend on abstractions, not on concretions “
When one class knows explicitly about the design and implementation of another class, changes to one class raise the risk of breaking the other class. To avoid such problems, you should write “good code” that is loosely coupled, and to support this you can turn to the Dependency Inversion Principle.  below is the problem
package com.kpblogs.solid_design_principles.dip;

public class Motor {

    public void motorOn() {

        System.out.println("Motor on...");
    }

    public void motorOff() {
        System.out.println("Motor off...");
    }

}

class Switch {

private Motor motor;

public Switch(Motor motor) {

// TODO Auto-generated constructor stub

this.motor = motor;

on = false;

}


boolean on;
public boolean isOn(){
return on;
}

public void press(){
        boolean checkOn = isOn();
        if (checkOn) {

            motor.motorOff();

            this.on = false;

        } else {
            motor.motorOn();
            this.on = true;
        }
    }

}

Our switch is now ready for use to turn on and off the Motor. But the mistake we did is apparent. Our high-level Switch class is directly dependent on the low-level Motor class. if you see in the code, the Motor class is hardcoded in Swicth. But, a switch should not be tied to a motor. It should be able to turn on and off other appliances and devices too, say a fan, an AC, or the entire lightning system. So solutions we can achieve with the help of loose coupling like below:

Now we are creating the interface with named “Swicthable” with two method turnOn() and turnOf(). and one more interface for the action means “Switch” to check if device is already running based on this option will press the button. In below section we have both interface “Switch and Switchable”

Switch.java
package com.kpblogs.solid_design_principles.dip;
public interface Switch {

boolean isOn();

void press();

}
Swicthable.java

package com.kpblogs.solid_design_principles.dip;
public interface Switchable {
  void turnOn();
  void turnOff();
}

below is the real use on different devices like for AC and Motor:

AC.java
package com.kpblogs.solid_design_principles.dip;
public class AC implements Switchable{

public void turnOn() {
  System.out.println("AC On");
}


public void turnOff() {
  System.out.println("AC Off");
}
}



Motor.java

package com.kpblogs.solid_design_principles.dip;

public class Motor implements Switchable{
public void turnOn() {

System.out.println("Motor On");
}

public void turnOff() {
  System.out.println("Motor Off");
}

}
Now its time to see the real implementation :
package com.kpblogs.solid_design_principles.dip;

public class PowerSwitch implements Switch {
 public Switchable client;
 public boolean on;
 public PowerSwitch(Switchable client) {
 this.client = client;
 this.on = false;
 }
 public boolean isOn() {
 return this.on;
 }
 public void press(){
 boolean checkOn = isOn();
 if (checkOn) {
 client.turnOff();
 this.on = false;
 } else {
 client.turnOn();
 this.on = true;
 } 
 }
}
That’s all and I hope it will help to someone please share your comments and feedback.  For full SOLID design principles example you can download from My Repo

810 total views, 1 views today

Leave a Reply

Your email address will not be published. Required fields are marked *