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

載入中......
此文章數據所有權由區塊鏈加密技術和智能合約保障僅歸創作者所有。