設計模式 (23種)& 面向對象思想的設計原則

面向對象思想的設計原則

1.單一職責原則
2.開閉原則
3.里氏替換原則
4.依賴注入原則
5.接口分離原則
6.迪米特原則java

1、單一職責原則

高內聚、低耦合:本身能作的,就不麻煩別人。
即:
每一個類應該只有一個職責,對外只能提供一種功能,而引發類變化的緣由應該只有一個,在設計模式中,全部的設計模式都遵循這一原則。面試

2、開閉原則(open closed principle)ocp原則

核心思想:一個對象對擴展開放,對修改關閉。
對類的改動是經過增長代碼進行的,而不是修改現有的代碼。
也就是說軟件開發人員一旦寫出了能夠運行的代碼,就不該該去改動它,而是要保證它能一直運行下去。這須要藉助於抽象和多態,即把可能變化的內容抽象出來,從而使抽象的部分是相對穩定的,而具體的實現則是能夠改變的和擴展的。編程

3、里氏替換原則

核心思想:在任何父類出現的地方均可以用它的子類來替代。即:同一個繼承體系中的對象,應該有共同的行爲特徵。設計模式

4、依賴注入原則

核心思想:要依賴於抽象,不要依賴於具體的實現。即在應用程序中,全部的類若是使用或依賴於其餘的類,則應該依賴於這些其餘類的抽象類,而不是這些其餘類的具體類。
爲了實現這一原則,就要求咱們在編程的時候針對抽象類或者接口編程,而不是針對具體的實現編程。安全

5、接口分離原則

核心思想:不該該強迫程序依賴他們不須要的方法,即 一個接口不須要提供太多的行爲,一個接口應該只提供一種對外的功能,不該該把全部的操做都封裝到一個接口中。多線程

6、迪米特原則

核心思想:一個對象應當對其餘的對象儘量的瞭解,即 下降個個對象間的耦合,提升系統的可維護性,在模塊間應該只經過接口編程,而不會理會模塊的內部工做原理,它可使各個模塊耦合度講到最低,促進軟件的複用。ide

總結:高內聚、低耦合、可複用。

設計模式(Design Pattern):經驗的總結

1.設計模式不是一種方法和技術,而是一種思想。
2.設計模式與具體的語言無關,學習設計模式就是要創建面向對象的思想,儘量的面向接口編程,高內聚、低耦合,使設計的程序可複用。
3.學習設計模式可以促進對面向對象思想的理解,反之亦然,它們相輔相成。

設計模式的分類

建立型模式: 對象的建立 (6個)
結構性模式: 對象的結構 (7個)
行爲型模式: 對象的行爲 (10個)性能

建立型模式
簡單工廠模式,工廠方法模式,抽象工廠模式,建造者模式,原型模式,單例模式。
結構性模式
外觀模式,適配器模式,代理模式,裝飾模式,橋接模式,組合模式,享元模式。
行爲型模式
模板方法模式,觀察者模式,狀態模式,職責鏈模式,命令模式,訪問者模式,策略模式,備忘錄模式,迭代器模式,解析器模式。
簡單工廠模式:
又叫靜態工廠方法模式,它定義了一個具體的工廠類,負責建立一些類的實例。

優勢:學習

客戶端不須要再負責對象的建立,從而明確了各個類的職責。

缺點:線程

這個靜態工廠類負責全部對象的建立,若是有新的對象增長(須要這個工廠類去建立新增長的這個對象),或者某些對象的建立方式不一樣,就須要不斷的修改工廠類,不利於後期的維護。(因而就有了工廠方法模式)
public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }
}
public class AnimalFactory {

    private AnimalFactory() {
    }

     public static Dog createDog() {
     return new Dog();
     }
    
     public static Cat createCat() {
     return new Cat();
     }    
}
public class AnimalDemo {
    public static void main(String[] args) {
        // 具體類調用
        Dog d = new Dog();
        d.eat();
        Cat c = new Cat();
        c.eat();
        System.out.println("------------");

        // 工廠有了後,經過工廠給造
         Dog dd = AnimalFactory.createDog();
         Cat cc = AnimalFactory.createCat();
         dd.eat();
         cc.eat();
         System.out.println("------------");
}
工廠方法模式:
工廠方法模式中的抽象工廠類(最好是個接口-好維護)負責定義建立對象的接口,具體對象的建立工做由繼承extends(實現implements)抽象工廠的具體類實現。

優勢:

客戶端不須要再負責對象的建立,從而明確了各個類的職責,若是有新的對象增長,只須要增長一個具體的類和具體的工廠類便可,不影響已有的代碼,後期維護容易,加強了系統的擴展性。

缺點:

須要額外的編寫代碼,增長工做量。
public interface Factory {
    //工廠接口 
    public abstract Animal createAnimal();
}
public class DogFactory implements Factory {

    @Override
    public Animal createAnimal() {
        return new Dog();
    }
}
public class CatFactory implements Factory {

    @Override
    public Animal createAnimal() {
        return new Cat();
    }
}
public abstract class Animal {
    public abstract void eat();
}
public class Dog extends Animal {

    @Override
    public void eat() {
        System.out.println("狗吃肉");
    }
}
public class Cat extends Animal {

    @Override
    public void eat() {
        System.out.println("貓吃魚");
    }
}
public class AnimalDemo {
    public static void main(String[] args) {
        // 需求:我要買只狗
        Factory f = new DogFactory(); // 多態
        Animal a = f.createAnimal();  // 多態
        a.eat();
        System.out.println("-------");
        
        //需求:我要買只貓
        f = new CatFactory();
        a = f.createAnimal();
        a.eat();
    }
}
單例模式:
如何確保是單例呢?
一個類在內存中只會加載一次,若是對象隨着類的加載而加載,對象不也就是一個嗎?
此時想到了static關鍵字。

餓漢式:類一加載,就建立對象。(是不會出現問題的單例模式)
懶漢式:用的時候,才建立對象。(可能出現問題的單例模式)

開發用餓漢式,面試用懶漢式

懶漢式設計兩個問題:
1.懶加載(延時加載)
2.線程安全問題(方法上加鎖synchronized-靜態方法,鎖對象爲類名.class)

a.是否有多線程環境
b.是否有共享數據
c.是否有多條語句操做共享數據

單例設計模式就是要要確保類在內存中只有一個對象,該實例必須自動建立,而且對外提供。
優勢:

在系統內存中只存在一個對象,所以能夠節約系統資源,對於一些須要頻繁建立和銷燬的對象,單例模式無疑能夠提升系統的性能。

缺點:

沒有抽象層,所以擴展很難。
指責很重,在必定程度上違背了單一職責。

餓漢式

public class Student {
    // 構造私有
    private Student() {
    }

    // 本身造一個
    // 靜態方法只能訪問靜態成員變量,加靜態
    // 爲了避免讓外界直接訪問修改這個值,加private(格外注意一下)
    private static Student s = new Student();

    // 提供公共的訪問方式
    // 爲了保證外界可以直接使用該方法,加靜態
    public static Student getStudent() {
        return s;
    }
}
/*
 * 單例模式:保證類在內存中只有一個對象。
 * 
 * 如何保證類在內存中只有一個對象呢?
 *         A:把構造方法私有
 *         B:在成員位置本身建立一個對象
 *         C:經過一個公共的方法提供訪問
 */
public class StudentDemo {
    public static void main(String[] args) {
        // Student s1 = new Student();
        // Student s2 = new Student();
        // System.out.println(s1 == s2); // false
        
        // 經過單例如何獲得對象呢?
        // Student.s = null;
        Student s1 = Student.getStudent();
        Student s2 = Student.getStudent();
        System.out.println(s1 == s2);

        System.out.println(s1); 
        System.out.println(s2);
    }
}

懶漢式:

/*
 * 單例模式:
 *         餓漢式:類一加載就建立對象
 *         懶漢式:用的時候,纔去建立對象
 * 
 * 面試題:單例模式的思想是什麼?請寫一個代碼體現。
 *      思想是:確保內存中的對象只有一份
 *         開發:餓漢式(是不會出問題的單例模式)
 *         面試:懶漢式(可能會出問題的單例模式)
 *             A:懶加載(延遲加載)    
 *             B:線程安全問題
 *                 a:是否多線程環境    是
 *                 b:是否有共享數據    是
 *                 c:是否有多條語句操做共享數據     是
 */
public class Teacher {
    private Teacher() {
    }

    private static Teacher t = null;
    // synchronized 關鍵字(格外注意-確保線程安全)
    public synchronized static Teacher getTeacher() {
        // t1,t2,t3
        if (t == null) {
            //t1,t2,t3
            t = new Teacher();
        }
        return t;
    }
}
public class TeacherDemo {
    public static void main(String[] args) {
        Teacher t1 = Teacher.getTeacher();
        Teacher t2 = Teacher.getTeacher();
        System.out.println(t1 == t2);
        System.out.println(t1); 
        System.out.println(t2);
    }
}

單例模式的應用:JDK的源碼

Runtime類 (餓漢式)

每一個Java應用程序都有一個Runtime類的實例,使應用程序可以與其運行的環境相鏈接。

exec(String command)
import java.io.IOException;

/*
 * Runtime:每一個 Java 應用程序都有一個 Runtime 類實例,使應用程序可以與其運行的環境相鏈接。
 * exec(String command)
 */
public class RuntimeDemo {
    public static void main(String[] args) throws IOException {
        Runtime r = Runtime.getRuntime();
//        r.exec("winmine");  //    打開掃雷
        // r.exec("notepad"); // 打開記事本
        // r.exec("calc"); // 打開計算器
//        r.exec("shutdown -s -t 10000"); //  10000s後關機
        r.exec("shutdown -a"); // 取消關機
    }
}

總結:單例模式三步走

第一步:私有化構造方法
第二步:在類的內部建立好對象
第三步:把已經建立好的對象返回給外部

class Runtime {
      private Runtime() {}
      private static Runtime currentRuntime = new Runtime();// 懶漢式-JDK源碼
      public static Runtime getRuntime() {
          return currentRuntime;
      }
  }
相關文章
相關標籤/搜索