Skip to content

Instantly share code, notes, and snippets.

Show Gist options
  • Save ibitebyt3s/7aa94cdfbe1ab126766f323306f6baa2 to your computer and use it in GitHub Desktop.
Save ibitebyt3s/7aa94cdfbe1ab126766f323306f6baa2 to your computer and use it in GitHub Desktop.
SOLID Design Principles in Java
public class Switch {
private Engine engine;
private boolean on;
public Switch(Engine engine) {
this.engine = engine;
this.on = false;
}
public boolean switchOn() {
return this.on;
}
public void flip() {
if (switchOn()) { this.on = false; engine.off(); }
else { this.on = true; engine.on(); }
}
}
// The Switch class is dependent on the Engine class which violates
// dependency inversion principle. It is tightly coupled with the Engine
// class, not reusable with any other objects. It can be designed as follows:
// High Level Classes (Switch) -> Abstraction Layer (SwitchClient) -> Low Level Classes (Engine)
public interface AbstractSwitch {
public boolean getState();
public void flip();
}
public interface SwitchClient {
public void on();
public void off();
}
public class Switch implements AbstractSwitch {
private SwitchClient client;
private boolean on;
public Switch(SwitchClient client) {
this.client = client;
}
public boolean getState() {
return this.on;
}
public void flip() {
if (getState()) { this.on = false; client.off(); }
else { this.on = true; client.on(); }
}
}
public class Engine implements SwitchClient {
public void on() {
System.out.println("Engine is on!");
}
public void off() {
System.out.println("Engine is off!");
}
}
Engine engine = new Engine();
Switch switch = new Switch(engine);
switch.flip();
switch.flip();
public interface IWorker {
public void work();
public void eat();
}
class Worker implements IWorker {
@Overwrite public void work() {
// Code
}
@Overwrite public void eat() {
// Code
}
}
// If we need support the new Robot class, we can split the IWorker interface as foolows:
interface IWorkable {
public void work();
}
interface IFeedable {
public void eat();
}
interface IWorker extends IWorkable, IFeedable {}
class Worker implements IWorker {
@Overwrite public void work() {
// Code
}
@Overwrite public void eat() {
// Code
}
}
class Robot implements IWorkable {
@Overwrite public void work() {
// Code
}
}
class Bird {
public void eat() {}
public void fly() {}
}
class Raven extends Bird {}
class Ostrich extends Bird {
fly() { throw new UnsupportedOperationException(); }
}
List<Bird> birds = new ArrayList<Bird>();
birds.add(new Bird());
birds.add(new Raven());
birds.add(new Ostrich());
for (Bird b : birds) { b.fly(); }
// The above code throws exception when an Ostrich instance is passed.
// The sub type Ostrich is not replaceable for the super type Bird.
// It can be designed as follows:
class Bird {
public void eat() {}
}
class FlyBird extends Bird {
public void fly();
}
class NonFlyBird extends Bird {}
public class EmailSender {
public void sendEmail(Object emailData, String formatType) {
String rContent = null;
if (formatType.equalsIgnoreCase("HTML")) {
rContent = renderInHtml(emailData);
} else if (formatType.equalsIgnoreCase("TEXT")) {
rContent = renderInText(emailData);
}
sendEmail(rContent);
}
private void sendEmail(String rContent) {
// Code
}
public String renderInHtml(Object emailData) {
// Code
}
public String renderInText(Object emailData) {
// Code
}
}
// If we need support JSON format, we need modify the existing code which violates the principle.
// It can be designed as follows for good extension:
public class EmailSender {
public void sendEmail(Object emailData, IReader render) {
String rContent = null;
rContent = render.render(emailData);
sendEmail(rContent);
}
private void sendEmail(String rContent) {
// Code
}
}
public interface IRender {
public String render(Object data);
}
public class HtmlRender implements IRender {
@Override public String render(Object data) {
// Code
}
}
public class TextRender implements IRender {
@Override public String render(Object data) {
// Code
}
}
public class JsonRender implements IRender {
@Override public String render(Object data) {
// Code
}
}
public class ServerConnectionManager {
public void createConnection(String host, String path, String port) {
// Code
}
public void sendRequest(Object request) {
// Code
}
}
// The above class provides two operations: make a connection and send a request.
// Two responsibilities are mixed up. It can be designed as follows:
public class ServerConnectionManager {
public void createConnection(String host, String path, String port) {
// Code
}
}
public class ServerConnection {
public void sendRequest(Object request) {
// Code
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment