banner
tiaotiaotang

tiaotiaotang

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

设计模式之七大设计原则

设计模式之七大设计原则#

1. 单一职责原则#

1.1 代码展示及 UML 类图#

反面案例

package singlePrinciple.negative;

public class StudentManager {
	public void getConnection(String url) {
		System.out.println("与"+url+"建立连接");
		
	}
	public void searchStudent(String condition) {
		System.out.println("根据"+condition+"查询学生信息");

	}
	public void deleteStudent(String condition) {
		System.out.println("根据"+condition+"删除学生信息");

	}
	public void display() {
		System.out.println("展示学生信息");

	}
	/**
	 * 1.修改连接的数据库方式,需要修改getConnection
	 * 
	 */
}

正面案列的 UML 类图

正面案列的 DBUtil.java

package singlePrinciple.positive;
//工具类
public class DBUtil {
	public void getConnection(String url) {
		System.out.println("与"+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("孙悟空");
		sm.display();
	}
	/**
	 * 1.DBUtil封装了数据库连接操作,更改数据库服务器仅仅只需要修改这个类或者配置文件
	 * 2.StudentDao封装了对数据库的增删改查的操作,实现增删改查比较方便
	 * 
	 */
}

然后 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("根据"+condition+"查询学生信息");

	}
	public void deleteStudent(String condition) {
		System.out.println("根据"+condition+"删除学生信息");

	}
}

最后的 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("展示学生信息");

	}

}

1.2 单一职责原则的定义及作用(简称 SRP)#

定义:一个类仅有一个引起它变化的原因,即一个对象应该只包含一个职责。这个是最简单,最容易理解却是最不容易做到的一个设计原则,用于控制类的粒度大小。

作用:

==1. 类的复杂度降低 ==

==2. 可读性提高 ==

==3. 可维护性提高 ==

==4. 对系统的扩展性和维护性有很大的帮助 ==

==5. 单一职责原则是实现高内聚,低耦合的指导方针 ==

2. 开闭原则(即开放封闭原则)#

2.1 代码展示#

暂时无

2.2 定义及作用(简称 OCP)#

1.” 对扩展开放 “:表示实体的行为是可以扩展的。当应用的需求改变时,可以对模块进行扩展,使其具有满足那些改变的新行为

2.“对修改关闭”:表示对实体进行扩展时,不必改动模块的源代码或者二进制代码。

作用:

==(1)有利于进行单元测试;==

==(2)可以提高复用性;==

==(3)提高可维护性;==

==(4)符合面向对象开放的要求;==

3. 接口隔离原则(简称 ISP)#

3.1 代码#

反面例子,未采用接口隔离的例子。

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("输出学生成绩!!!!!");
	}

	@Override
	public void search() {
		// TODO Auto-generated method stub
		
	}
	/*
	 * 存在接口污染
	 * 因为学生只能查询成绩,而不能修改,记录
	 * 如果实现接口,除了输出成绩,其他接口用不到
	 */

}

采用接口隔离原则后的案例 UML 如下:

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 定义及作用#

3.2.1 接口隔离原则:#

(1)客户端不应该依赖它不需要的接口;

(2)类之间的依赖关系应该建立在最新的接口上;

接口隔离原则是对接口的使用进行约束的一个原则

3.2.2 接口#

(1)类接口:使用 interface 定义的接口;

(2)实例接口:使用 Class 定义的类也是一种接口;

3.2.3 隔离#

==(1)客户端和它不需要的接口隔离,即客户端不使用它不需要的接口,使用该接口的客户端仅知道与之相关的方法;==

==(2)每一个接口应该承担一种相对独立的角色,不干不该干的事,该干的事都要干,接口中没有多余的方法。==

3.2.4 作用#

(1)避免接口感染;

(2)提高灵活性;

(3)提供制定服务;

(4)实现高内聚。

4. 依赖倒置原则(简称 DIP)#

4.1 代码#

4.1.1 不使用该原则案例如下#

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();
/**
 * 修改源代码,可能带来很多隐患,违反了开闭原则
 */
	}
}

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());
	}
	/**
	 * 如果此时要增加读取xml文件的功能,那就需要新建xlm读取功能类,然后再AutoRead方法中增加read此功能,这样违反了开闭原则
	 * 
	 */
}
package Dependency.negative;

public class DocRead {
	public void read() {
		System.out.println("读取doc文件!!!");

	}
}

package Dependency.negative;

public class ExlRead {
	public void read() {
		System.out.println("读取Excel文件!!");

	}
}

package Dependency.negative;

public class TextRead {
	public void read() {
		System.out.println("读取text文件!");

	}
}

package Dependency.negative;

public class XMLRead {
	public void read() {
		System.out.println("读取xml文件");

	}
}

4.1.2 使用原则案例如下:#

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("读取doc文件");
	}
	
}

package Dependency.positive;

public class ExlRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("读取xls文件。");
	}

}

package Dependency.positive;

public class TxtRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("读取txt文件。");
	}

}

package Dependency.positive;

public class XMLRead implements Readable{

	@Override
	public void read() {
		// TODO Auto-generated method stub
		System.out.println("读取xml文件");
	}

}

4.2 定义及作用#

4.2.1 定义:#

高层模块不应该依赖低层模块,他们都应该依赖抽象,抽象不应该依赖细节,细节应该依赖于抽象

本质就是通过抽象(接口或者抽象类)使各个类或模块的实现彼此独立,不互相影响,实现模块机间的松耦合。

4.2.2 作用:#

==(1)减少类间的耦合性;==

==(2)提高系统的稳定,降低并发开放引起的风险;==

==(3)提高代码的可读性和可维护性;==

5. 里氏替换原则(简称 LSP)#

5.1 代码#

5.1.1 反例代码:#

package substitution.negative;

public class ReadDoc extends ReadFile{

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

}

package substitution.negative;

public class ReadFile {
	public void read(String fileName) {
		System.out.println("读取excel文件"+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 正面案例:#

UML 如下:

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("读取doc文件:"+fileName);
	}
	
}

package substitution.positive;

public class ReadXsl implements Readable{

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

}

package substitution.positive;

/**
 * 
 * @author ASUS
 *继承有优点也有缺点
 *继承是侵入性的,增加了耦合
 */
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 定义及作用#

5.2.1 定义#

所有引用基类的地方必须能透明地使用其子类对象,即替换成子类之后,系统的行为不会发生变化。

里氏替换原则定义了继承关系要遵守的 4 个规则:

==(1) 子类可以实现父类的抽象方法,但不能覆写父类的非抽象方法;==

==(2) 子类中可以增加自己特有的方法,体现子类的个性;==

==(3) 当子类的方法实现父类的方法时 (重写 / 重载或实现抽象方法) 时,方法的前置条件 (即方法的输入参数) 要比父类方法的输入参数更宽松或相等;==

==(4) 当子类的方法实现父类的方法时 (重写 / 重载或实现抽象方法),方法的后置条件 (即方法的输出 / 返回值) 要比父类更严格或相等。==

5.2.2 作用#

(1)约束继承泛滥,开闭原则的一种体现;

(2)加强程序的健壮性,在程序变化可以做到非常好的兼容性,提高程序的维护性,扩展性;

(3)降低需求变更引入的风险。

6. 组合复用原则(简称 CRP)#

6.1 代码#

反面:

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("我是小学生");

	}
}
class JuniorStudent extends Student{
	public void say() {
		System.out.println("我是初中生");

	}
}
class HighStudent extends Student{
	public void say() {
		System.out.println("我是高中生");

	}
}
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) {
		
	}
}

正面:

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()+"是"+super.getLevel()+"老师");

	}
}

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()+"是"+super.getLevel()+"学生");

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

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

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

	@Override
	public String getLevel() {
		// TODO Auto-generated method stub
		return "高中";
	}
	
}
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()+"是"+super.getLevel()+"后勤管理人员");

	}
	
}
public class Demo {
	public static void main(String[] args) {
		SchoolLevel level=new HighLevel();
		Student swk=new Student("孙悟空",level);
		swk.say();
		Teacher puti=new Teacher("扶梯老祖",new PrimaryLevel());
		puti.say();
		Logistics cattle=new Logistics("牛魔王",new JuniorLevel());
		cattle.say();
	}
}

6.2 定义及作用#

6.2.1 定义#

优先使用对象组合(聚合),而不是继承来达到复用目的。

在一个新的对象里通过关联关系(包括组合和聚合关系) 来使用一些已有的对象,使之成为新对象的一部分,新对象通过委派调用已有对象的方法达到复用功能的目的。

即尽量使用组合(contains-a) 和聚合 (has-a), 而不是继承(is-a)达到复用的目的

6.2.2 作用#

(1)实现简单。通过继承,子类拥有父类的功能;

(2)易于扩展。子类通过增加新的属性和方法对父类进行扩展。

组合复用原则的作用

(1) 新对象存取成员对象的唯一途径是通过成员对象的接口,这种复用是黑箱复用,使系统更加灵活,降低类与类之间的耦合度;

(2) 成员对象的内部细节对新对象是不可见的,这种复用支持封装,减少依赖,一个类的变化对其他类造成的影响相对较少;

(3) 每一个新的类可以将焦点集中在一个任务上;

(4) 这种复用可以在运行时动态进行,新对象可动态引用与成员对象类型相同的对象。

不足之处:== 这种方式建造的系统会有较多的对象需要管理。==

7. 迪米特法则(LOD)#

不使用迪米特法则的例子

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+"文件内容!";
	}
	
	public void connectionDB() {
		System.out.println("连接"+this.db+"数据库系统");
	}
	public void save(String conten) {
		System.out.println("把"+this.read()+"保存在数据库中!!");

	}
	
}

客户端代码(客户端暴露的代码太多)

package lkp.negative;
//迪米特法则的反例
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);	

	}
}

迪米特法则的优点,== 客户端不需要知道如何转换,仅仅调用工具类的转换方法就能完成信息转换过程,客户端用最少知识完成了任务。==

迪米特法则:一个对象应当对其他的对象尽可能少的了解,不和陌生人说话,最少知识原则(==LKP==)。

尽可能减少对象之间的交互,如果一个对象需要调用另一个对象的方法,可以通过第三者调用。

朋友圈的成员:

==1. 当前对象本身(this)==

==2. 当前对象方法中的参数 ==

==3. 当前对象的实例变量之间引用的对象 ==

==4. 当前对象的实例变量如果是一个聚集,那么聚集的元素也是朋友 ==

==5. 当前对象方法所创建的对象 ==

四个要求:

== 优先考虑将一个类设置成不变类 ==

== 尽量降低一个类的访问权限 ==

== 谨慎使用 Serializable==

== 尽量降低成员的访问权限 ==

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 String read() {
		return this.fileName+"文件内容!";
	}
	
	private void connectionDB() {
		System.out.println("连接"+this.db+"数据库系统");
	}
	private void save(String conten) {
		System.out.println("把"+this.read()+"保存在数据库中!!");

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

中介者如下

package lkp.positive;

public class UtilConvert {
	private ExcelToDB todb;

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

客户端

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();
	}
}

加载中...
此文章数据所有权由区块链加密技术和智能合约保障仅归创作者所有。