banner
tiaotiaotang

tiaotiaotang

互联网科技爱好者/后端开发入门,学习ing
微信公众号

Seven Design Principles of Design Patterns

Seven Design Principles of Design Patterns#

1. Single Responsibility Principle#

1.1 Code Display and UML Class Diagram#

Negative Example

package singlePrinciple.negative;

public class StudentManager {
	public void getConnection(String url) {
		System.out.println("Connecting to "+url);
		
	}
	public void searchStudent(String condition) {
		System.out.println("Searching student information based on "+condition);

	}
	public void deleteStudent(String condition) {
		System.out.println("Deleting student information based on "+condition);

	}
	public void display() {
		System.out.println("Displaying student information");

	}
	/**
	 * 1. Modifying the database connection method requires changing getConnection
	 * 
	 */
}

Positive Example UML Class Diagram

Positive Example DBUtil.java

package singlePrinciple.positive;
// Utility class
public class DBUtil {
	public void getConnection(String url) {
		System.out.println("Connecting to "+url);
		
	}
}

Demo.java

package singlePrinciple.positive;

public class Demo {
	public static void main(String[] args) {
		DBUtil db=new DBUtil();
		StudentDao dao=new StudentDao(db);
		StudentManager sm=new StudentManager(dao);
		db.getConnection("MySQL");
		dao.searchStudent("Sun Wukong");
		sm.display();
	}
	/**
	 * 1. DBUtil encapsulates database connection operations, changing the database server only requires modifying this class or configuration files
	 * 2. StudentDao encapsulates CRUD operations on the database, making CRUD operations more convenient
	 * 
	 */
}

Then StudentDao.java

package singlePrinciple.positive;

public class StudentDao {
	
	private DBUtil db;
	
	public StudentDao(DBUtil db) {
		super();
		this.db = db;
	}
	public void searchStudent(String condition) {
		System.out.println("Searching student information based on "+condition);

	}
	public void deleteStudent(String condition) {
		System.out.println("Deleting student information based on "+condition);

	}
}

Final StudentManager.java

package singlePrinciple.positive;

public class StudentManager {
	private StudentDao dao;

	public StudentManager(StudentDao dao) {
		super();
		this.dao = dao;
	}
	public void display() {
		System.out.println("Displaying student information");

	}

}

1.2 Definition and Role of the Single Responsibility Principle (SRP)#

Definition: A class should have only one reason to change, meaning an object should only contain one responsibility. This is the simplest and easiest to understand yet the hardest design principle to implement, used to control the granularity of classes.

Role:

==1. Reduces class complexity==

==2. Improves readability==

==3. Enhances maintainability==

==4. Greatly aids the extensibility and maintainability of the system==

==5. The Single Responsibility Principle is a guideline for achieving high cohesion and low coupling==

2. Open-Closed Principle (OCP)#

2.1 Code Display#

None for now.

2.2 Definition and Role (OCP)#

  1. "Open for extension": Indicates that the behavior of an entity can be extended. When application requirements change, modules can be extended to have new behaviors that satisfy those changes.

  2. "Closed for modification": Indicates that when extending an entity, the source code or binary code of the module does not need to be modified.

Role:

==(1) Facilitates unit testing;==

==(2) Increases reusability;==

==(3) Improves maintainability;==

==(4) Complies with the requirements of object-oriented openness;==

3. Interface Segregation Principle (ISP)#

3.1 Code#

Negative Example, an example without interface segregation.

package InterfaceIsolation.negative;

public interface HandleScore {
	void update();
	void insert();
	void delete();
	void print();
	void search();
	
}

package InterfaceIsolation.negative;

public class Student implements HandleScore {

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void insert() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void delete() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void print() {
		// TODO Auto-generated method stub
		System.out.println("Outputting student scores!!!!");
	}

	@Override
	public void search() {
		// TODO Auto-generated method stub
		
	}
	/*
	 * There is interface pollution
	 * Because students can only query scores, not modify or record
	 * If implementing the interface, apart from outputting scores, other interfaces are not used
	 */

}

The UML after applying the Interface Segregation Principle is as follows:

package InterfaceIsolation.positive;

public interface Modifyable {
	void delete();
	void insert();

}
package InterfaceIsolation.positive;

public interface Printable {
	void print();

}
package InterfaceIsolation.positive;

public interface Searchable {
	void search();

}
package InterfaceIsolation.positive;

public interface Updateable {
	void update();

}
package InterfaceIsolation.positive;

public class Student implements Searchable{

	@Override
	public void search() {
		// TODO Auto-generated method stub
		
	}

}

package InterfaceIsolation.positive;

public class Teacher implements Searchable,Updateable,Printable{

	@Override
	public void print() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void update() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void search() {
		// TODO Auto-generated method stub
		
	}

}
package InterfaceIsolation.positive;

public class AcademicSecretary implements Modifyable,Printable,Searchable{

	@Override
	public void search() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void print() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void delete() {
		// TODO Auto-generated method stub
		
	}

	@Override
	public void insert() {
		// TODO Auto-generated method stub
		
	}

}

3.2 Definition and Role#

3.2.1 Interface Segregation Principle:#

(1) Clients should not depend on interfaces they do not need;

(2) Dependency relationships between classes should be established on the latest interfaces;

The Interface Segregation Principle is a principle that constrains the use of interfaces.

3.2.2 Interfaces#

(1) Class interfaces: Interfaces defined using interface;

(2) Instance interfaces: Classes defined using Class are also a type of interface;

3.2.3 Segregation#

==(1) Clients are isolated from interfaces they do not need, meaning clients do not use interfaces they do not need, and clients using the interface only know the methods related to it;==

==(2) Each interface should take on a relatively independent role, doing what it should do without unnecessary methods.==

3.2.4 Role#

(1) Avoid interface pollution;

(2) Increase flexibility;

(3) Provide tailored services;

(4) Achieve high cohesion.

4. Dependency Inversion Principle (DIP)#

4.1 Code#

4.1.1 Example Not Using the Principle#

package Dependency.negative;

public class AutoRead {
	public void read(TextRead r) {
		r.read();

	}
	public void read(DocRead r) {
		r.read();

	}
	public void read(ExlRead r) {
		r.read();

	}
	public void read(XMLRead r) {
		r.read();
		/**
		 * Modifying the source code may bring many hidden dangers, violating the Open-Closed Principle
		 */
	}
}

package Dependency.negative;

public class Demo {
	public static void main(String[] args) {
		AutoRead ar=new AutoRead();
		ar.read(new TextRead());
		ar.read(new DocRead());
		ar.read(new ExlRead());
	}
	/**
	 * If we need to add the functionality to read XML files, we need to create a new XML reading class and then add the read functionality in the AutoRead method, which violates the Open-Closed Principle
	 * 
	 */
}
package Dependency.negative;

public class DocRead {
	public void read() {
		System.out.println("Reading doc file!!!");

	}
}

package Dependency.negative;

public class ExlRead {
	public void read() {
		System.out.println("Reading Excel file!!");

	}
}

package Dependency.negative;

public class TextRead {
	public void read() {
		System.out.println("Reading text file!");

	}
}

package Dependency.negative;

public class XMLRead {
	public void read() {
		System.out.println("Reading xml file");

	}
}

4.1.2 Example Using the Principle#

package Dependency.positive;

public interface Readable {
	void read();
}

package Dependency.positive;

public class AutoRead{

	public void read(Readable r) {
		r.read();
	}
	
}

package Dependency.positive;

public class Demo {
	public static void main(String[] args) {
		AutoRead ar=new AutoRead();
		ar.read(new DocRead());
		ar.read(new ExlRead());
		ar.read(new TxtRead());
		ar.read(new XMLRead());
	}
}

package Dependency.positive;

public class DocRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("Reading doc file");
	}
	
}

package Dependency.positive;

public class ExlRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("Reading xls file.");
	}

}

package Dependency.positive;

public class TxtRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("Reading txt file.");
	}

}

package Dependency.positive;

public class XMLRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("Reading xml file");
	}

}

4.2 Definition and Role#

4.2.1 Definition:#

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.

Essentially, it is about making the implementations of various classes or modules independent of each other through abstraction (interfaces or abstract classes), achieving loose coupling between modules.

4.2.2 Role:#

==(1) Reduces coupling between classes;==

==(2) Increases system stability and reduces risks caused by concurrent changes;==

==(3) Improves code readability and maintainability;==

5. Liskov Substitution Principle (LSP)#

5.1 Code#

5.1.1 Negative Example Code:#

package substitution.negative;

public class ReadDoc extends ReadFile{

	@Override
	public void read(String fileName) {
		// TODO Auto-generated method stub
		System.out.println("Reading doc file:"+fileName);
	}
	

}

package substitution.negative;

public class ReadFile {
	public void read(String fileName) {
		System.out.println("Reading excel file"+fileName);

	}
}

package substitution.negative;
public class Demo {
	public static void readFile(ReadFile rf,String fileName) {
		rf.read(fileName);
	}
	public static void main(String[] args) {
		readFile(new ReadFile(),"a.xsl");
		readFile(new ReadDoc(),"b.xsl");
	}
}

5.1.2 Positive Example:#

UML as follows:

package substitution.positive;

public interface Readable {
	void read(String fileName);
}

package substitution.positive;

public class ReadDoc implements Readable{


	@Override
	public void read(String fileName) {
		// TODO Auto-generated method stub
		System.out.println("Reading doc file:"+fileName);
	}
	
}

package substitution.positive;

public class ReadXsl implements Readable{

	@Override
	public void read(String fileName) {
		// TODO Auto-generated method stub
		System.out.println("Reading Excel file:"+fileName);
	}
	

}

package substitution.positive;

/**
 * 
 * @author ASUS
 * Inheritance has advantages and disadvantages
 * Inheritance is invasive and increases coupling
 */
public class Demo {
	public static void readFile(Readable rf,String fileName) {
		rf.read(fileName);
	}
	public static void main(String[] args) {
		Readable r=new ReadDoc();
		readFile(r,"a.doc");
		ReadXsl rs=new ReadXsl();
		readFile(rs,"b.xsl");
	}
}

5.2 Definition and Role#

5.2.1 Definition#

All references to the base class must be able to transparently use its subclass objects, meaning that after replacing with a subclass, the system's behavior should not change.

The Liskov Substitution Principle defines four rules that must be followed in inheritance relationships:

==(1) Subclasses can implement abstract methods of the parent class but cannot override non-abstract methods of the parent class;==

==(2) Subclasses can add their unique methods, reflecting the individuality of the subclass;==

==(3) When a subclass's method implements a parent class's method (overrides/overloads or implements an abstract method), the preconditions (i.e., method input parameters) of the subclass's method should be more lenient or equal to those of the parent class's method;==

==(4) When a subclass's method implements a parent class's method (overrides/overloads or implements an abstract method), the postconditions (i.e., method output/return values) of the subclass should be stricter or equal to those of the parent class.==

5.2.2 Role#

(1) Constraints against excessive inheritance, reflecting the Open-Closed Principle;

(2) Strengthens the robustness of the program, allowing for excellent compatibility during program changes, improving maintainability and extensibility;

(3) Reduces risks introduced by requirement changes.

6. Composite Reuse Principle (CRP)#

6.1 Code#

Negative:

package combined.negative;
class Person{
	
}
class Teacher extends Person{
	
}
class Student extends Person{
	
}
class PrimarySchoolTeacher extends Teacher{
	
}
class JuniorSchoolTeacher extends Teacher{
	
}
class HighSchoolTeacher extends Teacher{
	
}
class PrimaryStudent extends Student{
	public void say() {
		System.out.println("I am a primary school student");

	}
}
class JuniorStudent extends Student{
	public void say() {
		System.out.println("I am a junior high school student");

	}
}
class HighStudent extends Student{
	public void say() {
		System.out.println("I am a high school student");

	}
}
class Logistics extends Person{
	
}
class PrimaryLigistics extends Logistics{
	
}
class JuniorLigistics extends Logistics{
	
}
class HighLigistics extends Logistics{
	
}

public class Demo {
	public static void main(String[] args) {
		
	}
}

Positive:

package combined.positive;

abstract class Person{
	private String name;
	private SchoolLevel level;
	public Person(String name, SchoolLevel level) {
		super();
		this.name = name;
		this.level = level;
	}
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
	public String getLevel() {
		return this.level.getLevel();
	}
	public void setLevel(SchoolLevel level) {
		this.level = level;
	}
	
}
class Teacher extends Person{

	public Teacher(String name, SchoolLevel level) {
		super(name, level);
		// TODO Auto-generated constructor stub
	}
	public void say() {
		System.out.println(super.getName()+" is a "+super.getLevel()+" teacher");

	}
}

class Student extends Person{

	public Student(String name, SchoolLevel level) {
		super(name, level);
		// TODO Auto-generated constructor stub
	}
	public void say() {
		System.out.println(super.getName()+" is a "+super.getLevel()+" student");

	}
	
}
interface SchoolLevel{
	String getLevel();
}
class PrimaryLevel implements SchoolLevel{

	@Override
	public String getLevel() {
		// TODO Auto-generated method stub
		return "Primary School";
	}
	
}
class JuniorLevel implements SchoolLevel{

	@Override
	public String getLevel() {
		// TODO Auto-generated method stub
		return "Junior High School";
	}
	
}
class HighLevel implements SchoolLevel{

	@Override
	public String getLevel() {
		// TODO Auto-generated method stub
		return "High School";
	}
	
}
class Logistics extends Person{

	public Logistics(String name, SchoolLevel level) {
		super(name, level);
		// TODO Auto-generated constructor stub
	}
	public void say() {
		System.out.println(super.getName()+" is a "+super.getLevel()+" logistics manager");

	}
	
}
public class Demo {
	public static void main(String[] args) {
		SchoolLevel level=new HighLevel();
		Student swk=new Student("Sun Wukong",level);
		swk.say();
		Teacher puti=new Teacher("Master Puti",new PrimaryLevel());
		puti.say();
		Logistics cattle=new Logistics("Bull Demon King",new JuniorLevel());
		cattle.say();
	}
}

6.2 Definition and Role#

6.2.1 Definition#

Prefer using object composition (aggregation) over inheritance to achieve reuse.

In a new object, use existing objects through association relationships (including composition and aggregation) to make them part of the new object, and the new object achieves reuse functionality by delegating calls to existing objects' methods.

That is, try to use composition (contains-a) and aggregation (has-a) rather than inheritance (is-a) to achieve reuse.

6.2.2 Role#

(1) Simple implementation. Through inheritance, subclasses inherit the functionality of the parent class;

(2) Easy to extend. Subclasses can extend the parent class by adding new attributes and methods.

The role of the Composite Reuse Principle:

(1) The only way for a new object to access member objects is through the interfaces of member objects, making this reuse black-box reuse, which makes the system more flexible and reduces coupling between classes;

(2) The internal details of member objects are invisible to the new object, supporting encapsulation, reducing dependencies, and minimizing the impact of changes in one class on others;

(3) Each new class can focus on a single task;

(4) This reuse can be dynamically performed at runtime, allowing new objects to dynamically reference objects of the same type as member objects.

Disadvantage: ==This approach results in a system with many objects to manage.==

7. Law of Demeter (LOD)#

An example of not using the Law of Demeter

package lkp.negative;

public class ExcelToDB {
	private String fileName;
	private String db;
	
	public ExcelToDB(String fileName, String db) {
		super();
		this.fileName = fileName;
		this.db = db;
	}
	
	public String read() {
		return this.fileName+" file content!";
	}
	
	public void connectionDB() {
		System.out.println("Connecting to "+this.db+" database system");
	}
	public void save(String conten) {
		System.out.println("Saving "+this.read()+" in the database!!");

	}
	
}

Client code (too much exposed code from the client)

package lkp.negative;
// An example against the Law of Demeter
public class Client {
	public static void main(String[] args) {
		ExcelToDB todb=new ExcelToDB("a.xsl","MySQL");
		String str=todb.read();
		todb.connectionDB();
		todb.save(str);	

	}
}

The advantage of the Law of Demeter is that ==the client does not need to know how to convert, it can complete the information conversion process just by calling the conversion method of the utility class, achieving the task with minimal knowledge.==

The Law of Demeter states that an object should have as little knowledge of other objects as possible, avoiding talking to strangers, following the principle of least knowledge (==LKP==).

It aims to minimize interactions between objects; if one object needs to call a method of another object, it can do so through a third party.

Friends of the circle:

==1. The current object itself (this)==

==2. Parameters in the current object's methods==

==3. Objects referenced by the current object's instance variables==

==4. If the current object's instance variable is an aggregate, then the elements of the aggregate are also friends==

==5. Objects created by the current object's methods==

Four requirements:

==Prefer to make a class immutable==

==Try to reduce the access permissions of a class==

==Be cautious when using Serializable==

==Try to reduce the access permissions of members==

package lkp.positive;

public class ExcelToDB {
	private String fileName;
	private String db;
	
	public ExcelToDB(String fileName, String db) {
		super();
		this.fileName = fileName;
		this.db = db;
	}
	// Private method to avoid exposure
	private String read() {
		return this.fileName+" file content!";
	}
	
	private void connectionDB() {
		System.out.println("Connecting to "+this.db+" database system");
	}
	private void save(String conten) {
		System.out.println("Saving "+this.read()+" in the database!!");

	}
	public void perform() {
		String str=this.read();
		this.connectionDB();
		this.save(str);
	}
	
}

Mediator as follows

package lkp.positive;

public class UtilConvert {
	private ExcelToDB todb;

	public UtilConvert(ExcelToDB todb) {
		super();
		this.todb = todb;
	}
	public void convert() {
		todb.perform();
	}
}

Client

package lkp.positive;

public class Client {
	public static void main(String[] args) {
		ExcelToDB todb=new ExcelToDB("a.xsl","MYSQL");
		UtilConvert convert=new UtilConvert(todb);
		convert.convert();
	}
}

Loading...
Ownership of this post data is guaranteed by blockchain and smart contracts to the creator alone.