天天看點

設計模式(java)———七大原則設計模式的目的

目錄

設計模式的目的

七大原則:

(1)單一原則

單一職責注意事項和細節

(2)接口隔離原則

(3)依賴倒轉原則

依賴倒轉原則的注意事項和細節:

(4)裡氏替換原則

(5)開閉原則

(6)迪米特法則

注意細節

(7)合成複用原則

設計模式的目的

編寫軟體的過程中,程式員面臨着來自耦合性,内聚性,可擴充性,維護性,靈活性。

  • 代碼重用性:相同的代碼不用重寫
  • 可讀性:便于閱讀和了解
  • 可擴充性:當擴充其他功能的時候友善
  • 可靠性:添加新功能時對其他的功能沒有影響
  • 程式呈現高内聚低耦合的特性

七大原則:

  • 單一原則
  • 接口原則
  • 依賴倒轉原則
  • 裡氏替換原則
  • 開閉原則
  • 迪米特原則
  • 合成複用原則

(1)單一原則

介紹:對類來說,一個類隻應該負責一個職責。

執行個體:

package com.kun.principle.singlersponsibilit;

public class SingleResponsibility1 {
	public static void main(String[] args) {
		/*
		 * 一個類(違反了單一原則)——》
		 * 三個類(使用了單一原則,但是消耗資源)——》
		 * 一個類三個方法(類上沒有展現單一原則,但是方法展現了)
		 * */
		AirVehicle vehicle1=new AirVehicle();
		vehicle1.run("feiji");
		RoadVehicle vehicle2=new RoadVehicle();
		vehicle2.run("qiche");
		WaterVehicle vehicle3=new WaterVehicle();
		vehicle3.run("zixingche");
	}
}
// 交通工具類
class AirVehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + " zai fei");
	}
}
class RoadVehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + " zai pao");
	}
}
class WaterVehicle{
	public void run(String vehicle) {
		System.out.println(vehicle + " zai you");
	}
}
           

單一職責注意事項和細節

  • 降低類的複雜度,一個類隻負責一項職責。
  • 提高類的可讀性,可維護性。
  • 降低變更引起的風險。
  • 通常情況下,我們應當遵守單一職責原則,除非邏輯足夠簡單。可以在方法上實作單一職責。

(2)接口隔離原則

介紹:一個類對另一個類的依賴,用接口來依賴,應當依賴最小組合的接口。如(A用B中的1,2,3接口,則應該拆分[1],[2,3])

執行個體:

package com.kun.principle.segregation;

public class Segregation {
	public static void main(String[] args) {
		A a=new A();
		a.depend1(new B());
	}
}
interface Interface1{
	void operation1();
	void operation2();
	void operation3();
	void operation4();
	void operation5();
}
class B implements Interface1{
	@Override
	public void operation1() {
		System.out.println("B 1");
	}
	@Override
	public void operation2() {
		System.out.println("B 2");
	}
	@Override
	public void operation3() {
		System.out.println("B 3");
	}
	@Override
	public void operation4() {
		System.out.println("B 4");
	}
	@Override
	public void operation5() {
		System.out.println("B 5");
	}
}
class A {
	public void depend1(Interface1 i) {
		i.operation1();
		i.operation2();
		i.operation3();
	}
}

           

改進版

package com.kun.principle.segregation;

public class improve {
	public static void main(String[] args) {
	}
}
interface inter1{
	void operation1();
}
interface inter2{
	void operation2();
	void operation3();
}
class B implements inter1,inter2{
	@Override
	public void operation1() {
		System.out.println("B 1");
	}
	@Override
	public void operation2() {
		System.out.println("B 2");
	}
	@Override
	public void operation3() {
		System.out.println("B 3");
	}
}
class A {
	public void depend1(inter1 i) {
		i.operation1();
	}
	public void depend2(inter2 i) {
		i.operation2();
		i.operation3();
	}
}


           

(3)依賴倒轉原則

介紹:

  • 高層子產品不應該依賴低層子產品,二者都應該依賴其抽象。
  • 抽象不應該依賴細節,細節應該依賴抽象。
  • 依賴倒轉的思想是面向接口程式設計。
  • 依賴倒轉原則是基于這樣的設計理念:相對于細節的多變性,抽象的東西要穩定的多。以抽象為基礎搭建的架構比以細節為基礎的架構要穩定的多。在java中,抽象指的是接口或抽象類,細節就是具體的實作類
  • 使用接口或抽象類的目的是制定好規範,而不涉及任何具體的操作,把展現細節的任務交給他們的實作類去完成

執行個體:

package com.kun.principle.inversion;

public class DependecyInversion {
	public static void main(String[] args) {
		//用戶端無需改變
		Person person =new Person();
		person.receive(new Email());
		person.receive(new WeiXin());
	}
}
interface IReceive{
	public String getInfo();
}
class Email implements IReceive{
	public String getInfo() {
		return "hello";
	}
}
class WeiXin implements IReceive{
	@Override
	public String getInfo() {
		return "weixin ok";
	}
}
//方式一:簡單,但是如果對象增加,相應的方法也要增加。
//		解決:是以要引入接口,對接口産生依賴
//class Person{
//	public void receive(Email email) {
//		System.out.println(email.getInfo());
//	}
//}
//方法二
class Person{
	public void receive(IReceive iReceive) {
		System.out.println(iReceive.getInfo());
	}
}
           

依賴倒轉原則的注意事項和細節:

  1. 低層子產品盡量都要有抽象類和接口
  2. 變量的聲明類型盡量是抽象類或接口
  3. 繼承時遵循裡氏替換原則

(4)裡氏替換原則

介紹:

  • 我們引用基類的地方必須能透明的使用其子類的對象
  • 在使用繼承時,在子類中盡量不要重寫父類的方法
  • 繼承讓兩個類的耦合性增強了,在适當的情況下可以使用聚合,組合,依賴

執行個體:

package com.kun.principle.liskov;

public class Liskov {
	public static void main(String[] args) {
		A a =new A();
		System.out.println("11-3="+a.fun1(11, 3));
		System.out.println("1-3="+a.fun1(1, 3));
		B b=new B();
		System.out.println("11+3="+b.fun1(11, 3));
		System.out.println("1+3="+b.fun1(1, 3));
		System.out.println("11+3+9="+b.fun2(11, 3));
		System.out.println("11-3="+b.fun3(11, 3));
	}
}
//解決方法
class Base{
	
}
class A extends Base{
	public int fun1(int num1,int num2) {
		return num1-num2;
	}
}
class B extends Base{
	private A a=new A();
	public int fun1(int a, int b) {
		return a+b;
	}
	public int fun2(int a,int b) {
		return fun1(a, b)+9;
	}
	public int fun3(int a,int b) {
		return this.a.fun1(a, b);
	}
}
//之前代碼,違背裡氏替換原則
//class A{
//	public int fun1(int num1,int num2) {
//		return num1-num2;
//	}
//}
//class B extends A{
//	public int fun1(int a, int b) {
//		return a+b;
//	}
//	public int fun2(int a,int b) {
//		return fun1(a, b)+9;
//	}
//}
           

(5)開閉原則

介紹:

  • 對一個軟體實體,子產品和函數應該擴充開放,對修改關閉。
  • 用抽象建構架構,用實作擴充細節
  • 通過擴充軟體實體的行為來變化,而不是修改
  • 程式設計中遵循各個原則,各個原則都遵循開閉原則。

執行個體:改進前

//缺點:增加一個其他圖形類,要建立一個類,然後在GraphicEditor添加判斷,添加方法,修改代碼太多
public class Ocp {
	public static void main(String[] args) {
		GraphicEditor graphicEditor=new GraphicEditor();
		graphicEditor.drawShape(new Rectangle());
		graphicEditor.drawShape(new Circle());
	}
}
class GraphicEditor{
	public void drawShape(Shape s) {
		if (s.m_type==1) {
			drawRectangle(s);
		}else if (s.m_type==2) {
			drawClircle(s);
		}
	}
	public void drawRectangle(Shape r) {
		System.out.println("ju xing");
	}
	public void drawClircle(Shape r) {
		System.out.println("yuan");
	}
}
class Shape{
	int m_type;
}
class Rectangle extends Shape{
	Rectangle(){
		super.m_type=1;
	}
}
class Circle extends Shape{
	Circle(){
		super.m_type=2;
	}
}
           

改進後的代碼:

package com.kun.principle.ocp;

public class Ocp {
	public static void main(String[] args) {
		GraphicEditor graphicEditor=new GraphicEditor();
		graphicEditor.drawShape(new Rectangle());
		graphicEditor.drawShape(new Circle());
	}
}
class GraphicEditor{
	public void drawShape(Shape s) {
		s.draw();
	}
}
abstract class Shape{
	public abstract void draw();
}
class Rectangle extends Shape{
	@Override
	public void draw() {
		System.out.println("ju xing");
	}
}
class Circle extends Shape{
	@Override
	public void draw() {
		System.out.println("yuan");
	}
}
           

(6)迪米特法則

介紹:

  • 一個對象應該對其他對象保持最少的了解
  • 類和類關系越密切。耦合度越大。
  • 迪米特法則又叫最少知道法則,即一個類對自己依賴的類知道的越少越好。也就是說,對于被依賴的類盡量把自己封裝起來,隻提供public方法。
  • 迪米特定義:隻和直接朋友通信

執行個體:

        建立一個對象

        周遊輸出對象

分析:

        SchoolManager的直接朋友類Employee

class SchoolManager
//傳回學枚總部的員工
public List<Employee>getAllEmployee(){
    List<Employee>list new ArrayList<Employee>();
    for(inti=0;i<5;i++){//這裡我們增加了5個員工到1ist
        Employee emp new Employee();
        emp.setId("學校總部員工id="+i);
        list.add(emp);
    }
       return list;
}
           

注意細節

  • 迪米特法則的核心是降低類之間的耦合
  • 但是注意:由于每個類都減少了不必要的依賴,是以迪米特法則隻是要求降低耦合

(7)合成複用原則

介紹:

  • 盡量使用合成和聚合的方式,而不是使用繼承。