<ruby id="bdb3f"></ruby>

    <p id="bdb3f"><cite id="bdb3f"></cite></p>

      <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
        <p id="bdb3f"><cite id="bdb3f"></cite></p>

          <pre id="bdb3f"></pre>
          <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

          <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
          <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

          <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                <ruby id="bdb3f"></ruby>

                合規國際互聯網加速 OSASE為企業客戶提供高速穩定SD-WAN國際加速解決方案。 廣告
                # 設計模式的七大原則 23種設計模式遵循的原則 1. 單一職責原則。 2. 接口隔離原則。 3. 依賴倒轉(倒置)原則。 4. 里氏替換原則。 5. 開閉原則ocp。 6. 迪米特法原則。 7. 合成復用原則。 達到目的: 1. 代碼重用性:相同功能的代碼,不用多次編寫。 2. 可讀性:編程規范,便于其他程序員閱讀。 3. 可擴展性:添加新功能時方便。 4. 可靠性:添加新功能后對原功能沒有影響。 5. 高內聚,低耦合。 &nbsp; ## 單一職責原則 單一職責原則指的是對類來說,一個類只負責一項職責,例如類A負責兩個不同的職責1和職責2,修改職責1的代碼會導致職責2執行出錯,這個時候就要將類A分解成類職責1和類職責2(粒度分解為A1和A2)。也可以從方法的級別分解不同的職責。 舉例如下: `SingleReposibility1.java` ~~~ ?zpackage cn.net.smrobot.design_principle; ?? ?public class SingleResponsibility1 { ? ? ?public static void main(String[] args) { ? ? ? ? ?Vehicle vehicle = new Vehicle(); ? ? ? ? ?vehicle.run("公交"); ? ? ? ? ?vehicle.run("汽車"); ? ? ? ? ?vehicle.run("飛機"); ? ? } ?? ?} ?/** ? * 方式1:這種方法違反了單一職責原則 ? * 例如傳入“飛機”等不應該用run來執行 ? * 解決方法:根據不同的交通工具,分解成不同的類 ? */ ?class Vehicle { ? ? ?public void run(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在公路上跑"); ? ? } ?} ? ? ~~~ 這種方式導致不同種類的對象調用了同一個方法,例如飛機并不能適用于run方法。 > 改進方式:根據不同的交通工具,分解成不同的工具類 `SingleResponsibility2.java` ~~~ ?package cn.net.smrobot.design_principle; ?? ?public class SingleResponsibility2 { ? ? ?public static void main(String[] args) { ? ? ? ? ?RoadVehicle roadVehicle = new RoadVehicle(); ? ? ? ? ?roadVehicle.run("摩托車"); ?? ? ? ? ? ?AirVehicle airVehicle = new AirVehicle(); ? ? ? ? ?airVehicle.run("飛機"); ?? ? ? ? ? ?WaterVehicle waterVehicle = new WaterVehicle(); ? ? ? ? ?waterVehicle.run("潛艇"); ? ? } ?} ?? ?/** ? * 方案二:遵守了單一職責原則 ? * 但是改動大,將類分解的同時修改了客戶端 ? * 改進:直接修改Vehicle類,而不修改其他類 ? */ ?class RoadVehicle{ ? ? ?public void run(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在公路上跑..."); ? ? } ?} ?class AirVehicle { ? ? ?public void run(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在天空上飛..."); ? ? } ?} ?class WaterVehicle{ ? ? ?public void run(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在水里游..."); ? ? } ?} ~~~ 這種方式就遵循了`類級別`的單一職責原則,但是由于修改添加了太多的類,改動太大。 > 改進方法:直接修改Vehicle類,而不用添加其他類 `SingleResponsibility3.java` ~~~ ?package cn.net.smrobot.design_principle; ?? ?public class SingleResponsibility3 { ? ? ?public static void main(String[] args) { ?? ? ? } ?} ?/** ? * 方式3:沒有對原來的類進行大修改,只是增加了方法 ? * 類級別上遵守單一職責原則,但是在方法上遵守了單一職責原則 ? */ ?class Vehicle1 { ? ? ?public void run(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在公路上跑"); ? ? } ?? ? ? ?public void runAir(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在天空飛..."); ? ? } ?? ? ? ?public void runWater(String vehicle) { ? ? ? ? ?System.out.println(vehicle + "在水里游..."); ? ? } ?? ?} ~~~ 這種方法通過增加方法的方式,在`方法級別`上遵守了單一職責原則,但是類級別上遵守單一職責原則. **總結** 1. 單一職責原則可以降低類的復雜度。 2. 提高代碼的可讀性,降低變更代碼引起的風險。 3. 如果類的邏輯簡單,類中方法數量足夠上,可以在方法級別上保證單一職責原則(`靜態工具類`)。 &nbsp; ## 接口隔離原則 Interface Segregation Principle 接口隔離原則指的是客戶端不應該依賴它不需要的接口,即一個類對另一個類的依賴應該建立在最小的接口上。 大致意思就是當一個類實現一個接口時,如果接口中的一些方法并不會通過該類的依賴被使用到,那么就不要去實現該接口的所有方法了,而是將該接口分解成多個更小的接口,使得實現這些接口的中的方法都會被使用到。 舉例: `InterfaceSegregation1.java` ~~~ ?package cn.net.smrobot.design_principle.interfaceSegregation; ?? ?/** ? * 接口隔離原則 ? */ ?public class InterfaceSegregation1 { ? ? ?public static void main(String[] args) { ?? ? ? } ?} ?? ?interface Interface1 { ? ? ?void method1(); ?? ? ? ?void method2(); ?? ? ? ?void method3(); ?? ? ? ?void method4(); ?? ? ? ?void method5(); ?} ?? ?/** ? * B實現接口 ? */ ?class B implements Interface1 { ? ? ?@Override ? ? ?public void method1() { ? ? ? ? ?System.out.println("B:method1"); ? ? } ? ? ?@Override ? ? ?public void method2() { ? ? ? ? ?System.out.println("B:method2"); ? ? } ? ? ?@Override ? ? ?public void method3() { ? ? ? ? ?System.out.println("B:method3"); ? ? } ? ? ?@Override ? ? ?public void method4() { ? ? ? ? ?System.out.println("B:method4"); ? ? } ? ? ?@Override ? ? ?public void method5() { ? ? ? ? ?System.out.println("B:method5"); ? ? } ?} ?? ?/** ? * D也實現接口 ? */ ?class D implements Interface1{ ? ? ?@Override ? ? ?public void method1() { ? ? ? ? ?System.out.println("D:method1"); ? ? } ? ? ?@Override ? ? ?public void method2() { ? ? ? ? ?System.out.println("D:method2"); ? ? } ? ? ?@Override ? ? ?public void method3() { ? ? ? ? ?System.out.println("D:method3"); ? ? } ? ? ?@Override ? ? ?public void method4() { ? ? ? ? ?System.out.println("D:method4"); ? ? } ? ? ?@Override ? ? ?public void method5() { ? ? ? ? ?System.out.println("D:method5"); ? ? } ?} ?? ?/** ? * A類通過接口依賴(使用)B類,但只會使用其中的1,2,3方法 ? */ ?class A { ? ? ?public void depend1(Interface1 interface1) { ? ? ? ? ?interface1.method1(); ? ? } ? ? ?public void depend2(Interface1 interface1) { ? ? ? ? ?interface1.method2(); ? ? } ? ? ?public void depend3(Interface1 interface1) { ? ? ? ? ?interface1.method3(); ? ? } ?} ?? ?/** ? * C 類通過接口依賴類D,但是只是會使用其中的1,4,5個方法 ? */ ?class C { ? ? ?public void depend1(Interface1 interface1) { ? ? ? ? ?interface1.method1(); ? ? } ? ? ?public void depend2(Interface1 interface1) { ? ? ? ? ?interface1.method4(); ? ? } ? ? ?public void depend3(Interface1 interface1) { ? ? ? ? ?interface1.method5(); ? ? } ?} ?? ~~~ > 因此需要將接口拆分成多個子接口 &nbsp; ## 依賴倒轉原則 `Dependence Inversion Principle` > 1. 高層模塊不要依賴底層模塊,二者都應該依賴其抽象 > > 2. 抽象不應該依賴細節,細節應該依賴抽象 > > 3. 中心思想就是面向接口編程 > > > 在java中,抽象指的是接口或者是抽象類,細節是對接口或抽象的實現 ~~~ ?public class DependenceInversion1 { ? ? ?public static void main(String[] args) { ? ? ? ? ?Person person = new Person(); ? ? ? ? ?person.receive(new Email()); ? ? } ?} ?? ?class Email { ? ? ?public String getInfo() { ? ? ? ? ?return "電子郵件信息:hello,world!"; ? ? } ?} ?? ?/** ? * 依賴的方法1: ? * 缺點:如果是其他信息來源(WeiXin),receive方法將不能使用 ? * 改進方法:引入一個抽象的接口IReceive,表示接受者,讓Person與接口IReceive發生依賴 ? */ ?class Person { ? ? ?public void receive(Email email) { ? ? ? ? ?System.out.println(email.getInfo()); ? ? } ?} ~~~ > Email參數設計為傳遞接口的方式 ~~~ ?public class DependenceInversion2 { ? ? ?public static void main(String[] args) { ? ? ? ? ?Person person = new Person(); ? ? ? ? ?person.receive(new Email()); ? ? } ?} ?? ?// 定義一個接受者接口 ?interface IReceive{ ? ? ?String getInfo(); ?} ?// 實現接口 ?class Email1 implements IReceive{ ? ? ?@Override ? ? ?public String getInfo() { ? ? ? ? ?return "電子郵件信息:hello,world!"; ? ? } ?} ?? ?class WeiXin implements IReceive { ?? ? ? ?@Override ? ? ?public String getInfo() { ? ? ? ? ?return "微信信息:hello,world!"; ? ? } ?} ?? ?/** ? * 依賴的方法2:將接口作為參數傳遞 ? * 依賴接口更加抽象,穩定性更好 ? */ ?class Person1 { ? ? ?public void receive(IReceive iReceive) { ? ? ? ? ?System.out.println(iReceive.getInfo()); ? ? } ?} ~~~ 依賴關系的實現: 1. 通過接口傳遞實現依賴 - 多態 `上面的例子` 2. 通過構造方法實現依賴 ~~~ ?interface IReceive { ? ? ?String getInfo(); ?} ?class Person { ? ? ?private IReceive iReceive; ? ? ?public Person(IReceive iReceive) { // 通過構造器傳遞一個已經實現好的接口實現類 ? ? ? ? ?this.iReceive = iReceive; ? ? } ?} ~~~ 3. 通過set方法實現依賴 ~~~ ?interface IReceive { ? ? ?String getInfo(); ?} ?class Person { ? ? ?private IReceive iReceive; ? ? ?// 通過set方法傳遞一個已經實現了接口的實現類 ? ? ?public setIReceive(IReceive iReceive) { ? ? ? ? ?this.iReceive = iReceive; ? ? } ?} ~~~ 總結: 1. 底層模塊盡量都要有抽象類或接口,會使程序的穩定性更好 2. 變量聲明類型盡量使用抽象類或接口,這樣我們在變量引用和實際對象間,就存在一個緩沖區,有利于程序擴展和優化 3. 繼承時遵循里氏替換原則 &nbsp; ## 里氏替換原則 面向對象中繼承體系的問題: 1. 增加程序之間的耦合性; 2. 如果一個父類被修改了,就要考慮其所有子類的功能,并且可能會導致所有子類的功能都故障; `如何正確使用繼承` = `盡量滿足里氏替換原則` > 如果對每個類型為T1的對象o1,都有類型T2的對象o2,使得在程序中用o2代替o1而不會對程序造成任何印象,即引用基類的地方必須能透明的使用其子類對象 * 在繼承時,子類盡量不要重寫父類的方法 * 在繼承中實際上是程序的耦合性增高,在適當情況下,可以通過聚合,組合,依賴來解決問題。 ~~~ ?package cn.net.smrobot.design_principle.liskov; ?? ?/** ? * 里氏替換原則 ? */ ?public class Liskov1 { ? ? ?public static void main(String[] args) { ? ? ? ? ?A a = new A(); ? ? ? ? ?System.out.println(a.fun1(10, 2)); ? ? ? ? ?System.out.println("------------------"); ? ? ? ? ?B b = new B(); ? ? ? ? ?System.out.println(b.fun1(10, 2)); ? ? ? ? ?System.out.println(b.fun2(10, 2)); ? ? } ?? ?? ?} ?? ?class A { ? ? ?public int fun1(int a, int b) { ? ? ? ? ?return a - b; ? ? } ?} ?? ?class B extends A { ? ? ?@Override ? ? ?public int fun1(int a, int b) { ? ? ? ? ?return a + b; ? ? } ? ? ?public int fun2(int a, int b) { ? ? ? ? ?return fun1(a, b) + 9; ? ? } ?} ~~~ 這里的fun1的方法被重寫了,可能導致想要的功能不準確。 > 在實際編程過程中,我們常常會通過重寫父類的方法完成新的功能,這樣寫會導致整個繼承體系的復用性差,特別是在運行多態比較頻繁的情況下。 > > 解決方法:取出原有的繼承關系,抽象一個更加基礎的基類。 修改方案: ~~~ ?package cn.net.smrobot.design_principle.liskov; ?? ?public class Liskov2 { ? ? ?public static void main(String[] args) { ?? ? ? } ?} ?? ?// 創建一個更加基礎的類 ?class Base { ?? ?} ?? ?class A1 extends Base{ ? ? ?public int fun1(int a, int b) { ? ? ? ? ?return a - b; ? ? } ?} ?? ?// B類不在繼承A類,如果B類要用到A類,可以用依賴,聚合等關系來替換 ?class B1 extends Base{ ? ? ?//B類使用A類中的方法 ? ? ?private A1 a1 = new A1(); ?? ? ? ?public int fun1(int a, int b) { ? ? ? ? ?return a + b; ? ? } ? ? ?public int fun2(int a, int b) { ? ? ? ? ?return fun1(a, b) + 9; ? ? } ?? ? ? ?// 用到A類中的方法 ? ? ?public int fun3(int a, int b) { ? ? ? ? ?return a1.fun1(a, b); ? ? } ?} ?? ~~~ 總結: 1. 繼承會帶來程序的入侵性,降低程序的可移植性。 2. 里氏替換原則用來指導正確的使用繼承關系。 &nbsp; ## 開閉原則 Open Closed Principle 開閉原則指的是,模塊和函數應該對擴展開放(提供方),對修改關閉(使用方),用抽象構建框架,用實現擴展細節。 當軟件需要變化時,盡量`通過擴展`軟件的實體行為來實現變化,而不是通過修改已有的代碼來實現變化。 **其他原則是為了實現開閉原則** ~~~ ?package cn.net.smrobot.design_principle.opendClose; ?? ?/** ? * 繪圖類 ? */ ?public class Ocp1 { ? ? ?public static void main(String[] args) { ? ? ? ? ?GraphicEditor graphicEditor = new GraphicEditor(); ? ? ? ? ?graphicEditor.drawShape(new Rectangle()); ? ? ? ? ?graphicEditor.drawShape(new Circle()); ? ? } ?} ?? ?/** ? * 繪制類 ? * 使用方 ? * 當添加繪制一個新的圖形時需要在使用方這里修改代碼 ? */ ?class GraphicEditor { ?? ? ? ?public void drawShape(Shape shape) { ? ? ? ? ?if (shape.type == 1) { ? ? ? ? ? ? ?drawRectangle(); ? ? ? ? } ? ? ? ? ?if (shape.type == 2) { ? ? ? ? ? ? ?drawCircle(); ? ? ? ? } ?? ? ? } ? ? ?public void drawRectangle() { ? ? ? ? ?System.out.println("繪制矩形"); ? ? } ?? ? ? ?public void drawCircle() { ? ? ? ? ?System.out.println("繪制圓形"); ? ? } ?? ?} ?? ?class Shape { ? ? ?public int type; ?} ?? ?class Rectangle extends Shape { ? ? ?public Rectangle() { ? ? ? ? ?this.type = 1; ? ? } ?} ?? ?class Circle extends Shape { ? ? ?public Circle() { ? ? ? ? ?this.type = 2; ? ? } ?} ~~~ > 改進思路:可以將Shape類改成抽象類,然后讓子類重寫各自的實現。 ~~~ ?package cn.net.smrobot.design_principle.opendClose; ?? ?/** ? * 繪圖類 ? */ ?public class Ocp1 { ? ? ?public static void main(String[] args) { ? ? ? ? ?GraphicEditor graphicEditor = new GraphicEditor(); ? ? ? ? ?graphicEditor.drawShape(new Rectangle()); ? ? ? ? ?graphicEditor.drawShape(new Circle()); ? ? } ?} ?? ?/** ? * 繪制類 ? * 直接調用draw方法,多態的思想 ? */ ?class GraphicEditor { ?? ? ? ?public void drawShape(Shape shape) { ? ? ? ? ?shape.draw(); ? ? } ? ? ? ?} ?? ?abstract class Shape { ? ? ?public int type; ? ? ? ? ? ?protected void draw(); ?} ?? ?class Rectangle extends Shape { ? ? ?public Rectangle() { ? ? ? ? ?this.type = 1; ? ? } ? ? ? ? ? ?@Override ? ? ?public void draw() { ? ? ? ? ?System.out.println("繪制矩形"); ? ? } ?} ?? ?class Circle extends Shape { ? ? ?public Circle() { ? ? ? ? ?this.type = 2; ? ? } ? ? ? ? ? ?@Override ? ? ?public void draw() { ? ? ? ? ?System.out.println("繪制圓形"); ? ? } ?} ?? ?class Triangle extends Shape { ? ? ?public Circle() { ? ? ? ? ?this.type = 2; ? ? } ? ? ? ? ? ?@Override ? ? ?public void draw() { ? ? ? ? ?System.out.println("繪制三角形"); ? ? } ?} ?? ~~~ 總結: 1. 對于使用方,盡量不要修改提供方的內容,而是擴展提供方的內容。 2. 盡量使用的抽象的方式來修改程序的功能。 &nbsp; ## 迪米特法則 Demeter Principle > 1. 一個對象應該對其他對象保持最少的了解。 > > 2. 又叫最少知道原則,即一個類對自己依賴的類知道得越少越好,即一個類盡量進行封裝。 > > 3. 更簡單的定義:只和直接朋友通信。 > 直接朋友: 將出現在`成員變量,方法參數,方法返回值`中的類稱為直接朋友,而以局部變量的方式出現的類不是直接朋友,因此別的類盡量不要以局部變量的方式出現在類的內部。 總計: 1. 迪米特法則用來降低類之間的耦合關系。 2. 只是盡量減少類之間的依賴關系,而不是完全不依賴。 &nbsp; ## 合成復用原則 > 盡量使用合成或者聚合的方式,而不是使用繼承的方式 &nbsp; ## 總結 1. 找出應用中可能需要變化之處,把它們獨立出來,不要和那些不需要變化的代碼混合在一起。 2. 面向接口編程,而不是面向實現編程。 3. 主要目的是讓代碼達到松耦合。 &nbsp; ## 類之間的關系 UML Unified Modeling Language 統一建模語言,是一套幫助軟件系統分析和設計的語言工具。 由一系列符號(類似于數學符號)和圖案組成用來表示**類之間的關系**。 由如下幾種關系: 1. Dependency 依賴 2. Association 關聯 3. Generalization 泛化/繼承 4. Realization 實現 5. Aggregation 聚合關系,關聯的一種,通過set方法引入 6. Composite 組合關系,關聯關系的一種,通過成員屬性A a = new A();的方法引入 **類圖分類** 1. 用例圖 use case 2. 靜態結構圖:`類圖`,對象圖,包圖,組件圖,部署圖 3. 動態行為圖:交互圖,狀態圖,活動圖 ## 依賴關系 只要在類中用到了對方,他們之間就存在依賴關系。 :-: ![](https://img.kancloud.cn/d7/bb/d7bba041108c554faced1921cb105e6d_534x306.png) 使用的位置: 1. 類的成員屬性 2. 方法的返回類型 3. 方法接收的參數類型 4. 方法中的局部變量。 &nbsp; ## 泛化和實現關系 泛化關系:繼承關系,也是依賴關系的一種特例。 :-: ![](https://img.kancloud.cn/87/a3/87a3fac7acd4ff3d865aafcb031acaff_251x262.png) 實現關系:即A類實現B接口,也是依賴關系的一種特例。 :-: ![](https://img.kancloud.cn/ea/10/ea106f5d46d2906c6aff34c756ec81a9_289x250.png) &nbsp; ## 關聯關系 類與類之間的關系,是依賴關系的一種特例。 關聯關系具有導航性:即雙向關系或單向關系。 ~~~ ?// 單向一對一關系 ?public class Person() { ? ? ?private IDCard card; ?} ?public class IDCard() {} ?? ?// 雙向一對一關系 ?public class Person() { ? ? ?private IDCard card; ?} ?public class IDCard() { ? ? ?private Person person; ?} ~~~ &nbsp; ## 聚合關系 表示整體和部分的關系,`整體和部分可以分開`,聚合關系是關聯關系的特例。具有導航性和多重性。`對象的引入通過set方法或者構造方法`實現。 ~~~ ?// 鼠標類和顯示器類都可以和Computer類分開,因此是聚合關系 ?public class Computer{ ? ? ?private Mouse mouse; ? ? ? ? ? ?private Monitor monitor; ? ? ? ? ? ?// set方法 ? ? ? ?} ~~~ :-: ![](https://img.kancloud.cn/68/48/68481131c3d904a590f16d170ff92def_515x203.png) &nbsp; ## 組合關系 整體和部分是不可以分開的稱為組合關系,對象的引入通過直接new實現。 ~~~ ?// 鼠標類和顯示器類在Computer一創建就會被創建,因此是不可分割的,屬于組合關系 ?public class Computer{ ? ? ?private Mouse mouse = new Mouse(); ? ? ? ? ? ?private Monitor monitor = new Mouse(); ? ? ? ?} ~~~ :-: ![](https://img.kancloud.cn/33/fe/33fe059712904edc38053815ef7c016d_595x215.png) 聚合關系和組合關系是可以混合使用,主要是看整體和部分是否可以分開。 > 如果Person類中定義了對IDCard的級聯刪除,那么Person類和IDCard類就是組合關系。不一定直接使用new才是組合關系。
                  <ruby id="bdb3f"></ruby>

                  <p id="bdb3f"><cite id="bdb3f"></cite></p>

                    <p id="bdb3f"><cite id="bdb3f"><th id="bdb3f"></th></cite></p><p id="bdb3f"></p>
                      <p id="bdb3f"><cite id="bdb3f"></cite></p>

                        <pre id="bdb3f"></pre>
                        <pre id="bdb3f"><del id="bdb3f"><thead id="bdb3f"></thead></del></pre>

                        <ruby id="bdb3f"><mark id="bdb3f"></mark></ruby><ruby id="bdb3f"></ruby>
                        <pre id="bdb3f"><pre id="bdb3f"><mark id="bdb3f"></mark></pre></pre><output id="bdb3f"></output><p id="bdb3f"></p><p id="bdb3f"></p>

                        <pre id="bdb3f"><del id="bdb3f"><progress id="bdb3f"></progress></del></pre>

                              <ruby id="bdb3f"></ruby>

                              哎呀哎呀视频在线观看