目錄
設計模式的目的
七大原則:
(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());
}
}
依賴倒轉原則的注意事項和細節:
- 低層子產品盡量都要有抽象類和接口
- 變量的聲明類型盡量是抽象類或接口
- 繼承時遵循裡氏替換原則
(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)合成複用原則
介紹:
- 盡量使用合成和聚合的方式,而不是使用繼承。