第8篇-JAVA面向對象-設計模式Ⅳ

第8篇-JAVA面向對象-設計模式Ⅳ

  • 每篇一句 : 想象是程序的創作之源

  • 初學心得 : 平靜的海洋練不出熟練的水手

  • (筆者:JEEP/711)[JAVA筆記 | 時間:2017-04-11| JAVA面向對象 Ⅳ]

JAVA設計模式

什麼是JAVA設計模式以及作用? 
設計模式是一套被反覆使用、多數人知曉的、經過分類編目的、代碼設計經驗的總結 
使用設計模式是爲了可重用代碼、讓代碼更容易被他人理解、保證代碼可靠性,本篇將介紹10種JAVA常用設計模式

1.JAVA 設計模式 - 單例設計模式

單例模式是一種創建模式,這種模式只涉及一個單獨的類,它負責創建自己的對象 
該類確保只創建單個對象,這個類提供了一種訪問其唯一對象的方法 
單例模式目的是爲了整個應用中有且只有一個實例,所有指向該類型實例的引用都指向這個實例 
保證對象不能再類的外部被隨意實例化,解決方法:將構造器進行私有化處理 
保證類創建的過程發生在類的內部,還有保證在類的外部能拿到在類的內部初始化的對象

單例模式類型:餓漢式單例,懶漢式單例

Singleton(餓漢模式) 
餓漢模式,特點是程序加載類的時候比較慢,但運行時獲得對象的速度比較快,它從加載到應用結束會一直佔用資源 
餓漢模式代碼:

1.class Singleton {
2.       public class SingletonDemo {
3.  public static void main(String[] args) {
4.      Singleton1 s1 = Singleton1.getInstance();
5.      Singleton1 s2 = Singleton1.getInstance();
6.      System.out.println(s1==s2);  //true
7.      Singleton2 s3 = Singleton2.getInstance();
8.      Singleton2 s4 = Singleton2.getInstance();
9.      System.out.println(s3==s4);  //true
10.  }
11.}
12.class Singleton1{
13.  private static final Singleton1 instance = new Singleton1();  //在內部準備好一個對象  
14.  public static Singleton1 getInstance(){
15.      return instance;
16.  }
17.  private Singleton1(){}
18.  public void show(){
19.      System.out.println("Singleton1");
20.  }
21.}
22.class Singleton2 {
23.  private static Singleton2 instance;
24.  //將instance傳遞到外部去
25.  public static Singleton2 getInstance(){ 
26.      if(instance == null){
27.          instance = new Singleton2();
28.      }
29.      return instance;
30.  }
31.  private Singleton2(){}
32.}

Singleton(懶漢模式) 
懶漢模式特點,程序是運行時獲得對象的速度比較慢,但加載類的時候比較快 
它在整個應用的生命週期只有一部分時間在佔用資源 
懶漢模式代碼:

1.class Singleton{
2.  private static Singleton instance = null;
3.  public static Singleton getInstance(){// 將instance傳遞到外部去
4.      if(instance == null){
5.          instance = new Singleton();
6.      }
7.      return instance;
8.  }
9.  private Singleton(){}
10.}
11.public static Singleton2 getInstance(){
12.     if(instance == null){
13.        synchronized(Singleton2.class){
14.             if(instance == null){
15.                instance = new Singleton2(); 
16.              }
17.          }
18.     }     
19.   return instance;
20.  }

Singleton(餓漢模式) & Singleton(懶漢模式) 區別 
(1)這兩種模式對於初始化較快,佔用資源少的輕量級對象來說,沒有多大的性能差異,選擇懶漢式或餓漢式都沒有問題
但是對於初始化慢,佔用資源多的重 量級對象來說,就會有比較明顯的差別了 
所以,對重量級對象應用餓漢模式,類加載時速度慢,但運行時速度快;懶漢模式則與之相反,類加載時速度快,但運行時第一次獲得對象的速度慢 
(2)從用戶體驗的角度來說,我們應該首選餓漢模式。我們願意等待某個程序花較長的時間初始化,卻不喜歡在程序運行時等待太久,給人一種反應遲鈍的感覺,所以對於有重量級對象參與的單例模式,筆者推薦使用餓漢模式

2.JAVA設計模式 - 享元設計模式

在JAVA語言中,String類型就是使用了享元模式。String對象是final類型,對象一旦創建就不可改變 
在JAVA中字符串常量都是存在常量池中的,JAVA會確保一個字符串常量在常量池中只有一個拷貝 
String a=”abc”,其中”abc”就是一個字符串常量 
享元模式代碼:

1.public class Test {
2.   public static void main(String[] args) {
3.       String a = "abc";
4.       String b = "abc";
5.       System.out.println(a == b);
6.   }
7.}

上面的例子中結果爲:true ,這就說明a和b兩個引用都指向了常量池中的同一個字符串常量”abc” 
這樣的設計避免了在創建N多相同對象時所產生的不必要的大量的資源消耗

3.JAVA設計模式 - 簡單工廠設計模式

簡單工廠模式是由一個工廠對象決定創建出哪一種產品類的實例 
簡單工廠模式是工廠模式家族中最簡單實用的模式,工廠模式就是用來生成對象的 
簡單工廠設計模式作用:降低耦合

簡單工廠模式代碼:

1.//手機標準
2.interface ICellPhone {
3.  void sendMsg();
4.}
5./* 小米手機 */
6.class Millet implements ICellPhone {
7.  public void sendMsg() {
8.  }
9.}
10./* 華爲手機 */
11.class Huawei implements ICellPhone {
12.  public void sendMsg() {
13.  }
14.}
15./* 手機工廠 */
16.class Factory {
17.  public static ICellPhone getInstance(String type){
18.      ICellPhone phone = null;
19.      if("millet".equalsIgnoreCase(type)){
20.          phone = new Millet();
21.      }else if("huawei".equalsIgnoreCase(type)){
22.          phone = new Huawei();
23.      }
24.      return phone;
25.  }
26.}
27.public class FactoryDemo {
28.  public static void main(String[] args) {
29.      ICellPhone p = Factory.getInstance("millet");
30.  }
31.}

如果直接使用了被調用者對象,而且又有可能會變化,那這個代碼的可擴展性和柔韌性就不是很強基於這樣的問題,所有我們就提出把客戶端(調用者)不直接跟要調用的對象產生依賴關係,這樣在擴展性和柔韌性會好一些,加入中間人,來引入工廠模式調控,單獨聲明一個工廠類,屬於被調用者這一邊,簡單工廠類只負責產生對象

4.JAVA設計模式 - 抽象工廠設計模式

抽象工廠模式與簡單工廠模式的區別: 
(1)抽象工廠模式是簡單工廠方法模式的升級版本,它用來創建一組相關或者相互依賴的對象。它與簡單工廠方法模式的區別就在於,簡單工廠方法模式針對的是一個產品等級結構;而抽象工廠模式則是針對的多個產品等級結構 
(2)在編程中,通常一個產品結構,表現爲一個接口或者抽象類,也就是說,簡單工廠方法模式提供的所有產品都是衍生自同一個2接口或抽象類,而抽象工廠模式所提供的產品則是衍生自不同的接口或抽象類 
(3)在抽象工廠模式中,有一個產品族的概念:所謂的產品族,是指位於不同產品等級結構中功能相關聯的產品組成的家族。抽象工廠模式所提供的一系列產品就組成一個產品族;而工廠方法提供的一系列產品稱爲一個等級結構

抽象工廠模式代碼:

1.interface IProduct1 {
2.       public void show();
3.   }
4.   interface IProduct2 {
5.       public void show();
6.   }
7.   class Product1 implements IProduct1 {
8.       public void show() {
9.           System.out.println("這是1型產品");
10.       }
11.   }
12.   class Product2 implements IProduct2 {
13.       public void show() {
14.           System.out.println("這是2型產品");
15.       }
16.   }
17.   interface IFactory {
18.       public IProduct1 createProduct1();
19.       public IProduct2 createProduct2();
20.   }
21.   class Factory implements IFactory{
22.       public IProduct1 createProduct1() {
23.           return new Product1();
24.       }
25.       public IProduct2 createProduct2() {
26.           return new Product2();
27.       }
28.   }
29.   public class Client {
30.       public static void main(String[] args){
31.           IFactory factory = new Factory();
32.           factory.createProduct1().show();
33.           factory.createProduct2().show();
34.       }
35.   }

抽象工廠模式的優點: 
抽象工廠模式除了具有簡單工廠方法模式的優點外,最主要的優點就是可以在類的內部對產品族進行約束,所謂的產品族,一般或多或少的都存在一定的關聯,抽象工廠模式就可以在類內部對產品族的關聯關係進行定義和描述,而不必專門引入一個新的類來進行管理 
抽象工廠模式的缺點: 
產品族的擴展將是一件十分費力的事情,假如產品族中需要增加一個新的產品,則幾乎所有的工廠類都需要進行修改,所以使用抽象工廠模式時,對產品等級結構的劃分是非常重要的 
適用場景 
當需要創建的對象是一系列相互關聯或相互依賴的產品族時,便可以使用抽象工廠模式,說的更明白一點,就是一個繼承體系中,如果存在着多個等級結構(即存在着多個抽象類),並且分屬各個等級結構中的實現類之間存在着一定的關聯或者約束,就可以使用抽象工廠模式,假如各個等級結構中的實現類之間不存在關聯或約束,則使用多個獨立的工廠來對產品進行創建,則更合適一點

5.JAVA設計模式 - 裝飾設計模式

裝飾模式在不鏈接其結構的情況下向現有對象添加新功能,它是一種結構型模式,因爲它充當現有類的包裝器 
裝飾模式創建一個裝飾器類來包裝原始類並提供其他功能 
裝飾模式代碼:

1.interface Printer {
2.  void print();
3.}
4.
5.class PaperPrinter implements Printer {
6.  @Override
7.  public void print() {
8.     System.out.println("Paper Printer");
9.   }
10.}
11.
12.class PlasticPrinter implements Printer {
13.  @Override
14.  public void print() {
15.     System.out.println("Plastic Printer");
16.   }
17.}
18.
19.abstract class PrinterDecorator implements Printer {
20.  protected Printer decoratedPrinter;
21.  public PrinterDecorator(Printer d){
22.     this.decoratedPrinter = d;
23.  }
24.  public void print(){
25.     decoratedPrinter.print();
26.   }  
27.}
28.
29.class Printer3D extends PrinterDecorator {
30.  public Printer3D(Printer decoratedShape) {
31.     super(decoratedShape);    
32.  }
33.  @Override
34.  public void print() {
35.    System.out.println("3D.");
36.    decoratedPrinter.print();         
37.   }
38.}
39.
40.public class Main {
41.  public static void main(String[] args) {
42.     Printer plasticPrinter = new PlasticPrinter();
43.     Printer plastic3DPrinter = new Printer3D(new PlasticPrinter());
44.     Printer paper3DPrinter = new Printer3D(new PaperPrinter());
45.     plasticPrinter.print();
46.     plastic3DPrinter.print();
47.     paper3DPrinter.print();
48.   }
49.}

6.JAVA設計模式 - 觀察者設計模式

定義對象間一種一對多的依賴關係,使得當每一個對象改變狀態,則所有依賴於它的對象都會得到通知並自動更新 
觀察者模式中,包括以下四個角色: 
(1)被觀察者:類中有一個用來存放觀察者對象的Vector容器(之所以使用Vector而不使用List,是因爲多線程操作時,Vector在是安全的,而List則是不安全的),這個Vector容器是被觀察者類的核心,另外還有三個方法:attach方法是向這個容器中添加觀察者對象;detach方法是從容器中移除觀察者對象;notify方法是依次調用觀察者對象的對應方法。這個角色可以是接口,也可以是抽象類或者具體的類,因爲很多情況下會與其他的模式混用,所以使用抽象類的情況比較多 
(2)觀察者:觀察者角色一般是一個接口,它只有一個update方法,在被觀察者狀態發生變化時,這個方法就會被觸發調用 
(3)具體的被觀察者:使用這個角色是爲了便於擴展,可以在此角色中定義具體的業務邏輯 
(4)具體的觀察者:觀察者接口的具體實現,在這個角色中,將定義被觀察者對象狀態發生變化時所要處理的邏輯

觀察者模式代碼實現:

1.abstract class Subject {
2.       private Vector obs = new Vector();
3.       public void addObserver(Observer obs){
4.           this.obs.add(obs);
5.       }
6.       public void delObserver(Observer obs){
7.           this.obs.remove(obs);
8.       }
9.       protected void notifyObserver(){
10.          for(Observer o: obs){
11.               o.update();
12.           }
13.       }
14.       public abstract void doSomething();
15.   }
16.   class ConcreteSubject extends Subject {
17.       public void doSomething(){
18.           System.out.println("被觀察者事件");
19.           this.notifyObserver();
20.       }
21.   }
22.   interface Observer {
23.       public void update();
24.   }
25.   class ConcreteObserver1 implements Observer {
26.       public void update() {
27.           System.out.println("觀察者1收到信息進行處理");
28.       }
29.   }
30.   class ConcreteObserver2 implements Observer {
31.       public void update() {
32.           System.out.println("觀察者2收到信息進行處理");
33.       }
34.   }
35.   public class Client {
36.       public static void main(String[] args){
37.           Subject sub = new ConcreteSubject();
38.           sub.addObserver(new ConcreteObserver1());  //添加觀察者1
39.           sub.addObserver(new ConcreteObserver2());  //添加觀察者2
40.           sub.doSomething();
41.       }
42.   }

觀察者模式的優點:觀察者與被觀察者之間是屬於輕度的關聯關係,並且是抽象耦合的,這樣對於兩者來說都比較容易進行擴展,觀察者模式是一種常用的觸發機制,它形成一條觸發鏈,依次對各個觀察者的方法進行處理,但同時,這也算是觀察者模式一個缺點,由於是鏈式觸發,當觀察者比較多的時候,性能問題是比較令人擔憂的。並且,在鏈式結構中,比較容易出現循環引用的錯誤,造成系統假死

7.JAVA設計模式 - 適配器設計模式

在JAVA設計模式中,適配器模式作爲兩個不兼容接口之間的橋樑 
通過使用適配器模式,可以統一兩個不兼容的接口 
適配器設計模式代碼:

1.//適配器模式
2.public class Shipeiqi{
3.  public static void main(String [] args){
4.      ModificationWindow i = new ModificationWindow();
5.      i.close();  
6.   }
7.}
8.
9.//定義一個接口
10.interface IWindow{
11.  void man();//只聲明方法,
12.  void min();//只聲明方法
13.   void close();//只聲明方法,
14.}
15.
16.//定義一個抽象實現
17.abstract class MyWindow implements IWindow{
18.  public void man(){};
19.  public void min(){};
20.  public void close(){};
21.}
22.
23.//定義一個類繼承接口
24.class ModificationWindow extends MyWindow{
25.  public void close(){
26.      System.out.println("我將實現關閉功能");
27.   }
28.}

8.JAVA設計模式 - 靜態代理設計模式

靜態代理設計模式:如生活當中的代理,代駕,代購,待產… 
代理模式(Proxy):爲其他對象提供一種代理以控制對這個對象的訪問 
代理模式,白了就是“真實對象”的代表,在訪問對象時引入一定程度的間接性,因爲這種間接性可能附和多種用途(權限的控制、對象的訪問、遠程的代理) 
代理類第一先要實現接口,第二要維護一個代理的對象,代理對象也是通過主題接口聲明的,再通過構造方法或者get,set傳值,這就是靜態代理

靜態代理模式代碼:

1.//靜態代理設計模式
2.
3.//聲明一個類
4.public class Jingtai{
5.  //主方法
6.  public static void main(String [] args){
7.      Person p = new Person("老王 ");//實例化Person對象
8.      //創建代理對象,並把被代理對象傳進來,p傳給了Matchmaker類中的target
9.      Matchmaker m = new Matchmaker(p); //需要一個代理對象,把被代理對象傳過來
10.      m.miai();//真正執行調用的是     
11.   }
12.}
13.
14.//定義一個接口  主題接口
15.interface Subject{
16.  public void miai();//抽象方法
17.}
18.
19.//代理相當於代理接口的方法
20.//定義實現一個接口,相當於被代理類
21.class Person implements Subject{
22.  private String name;//定義私有的屬性
23.  //一參構造方法
24.  public Person(String name){
25.      this.name = name;
26.  }
27.
28.  //定義實現方法
29.  public void miai(){
30.      System.out.println(name+"正在相親中...");//輸出
31.   }
32.}
33.
34.//定義一個代理類,代理的是過程,實現以後,是爲了實現方法,需要重寫方法
35.class Matchmaker implements Subject{
36.  private Subject target;//要代理的目標對象,通過定義一個代理的對象實現的接口,代理一個對象或者說一個屬性,
37.  //可以用構造方法傳值,也可以用get,set方法傳值
38.  //構造方法傳值
39.  public Matchmaker(Subject target){
40.      this.target = target;
41.  }
42.
43.  //相親之前要做的事情,封裝起來
44.  private void before(){
45.      System.out.println("爲代理人,匹配如意郎君");
46.  }
47.
48.  //相親之後要做的事情
49.  private void after(){
50.      System.out.println("本次相親結束.");  
51.  }
52.
53.  //需要重寫方法,相親的方法
54.  public void miai(){
55.      before();//調用相親之前要做的事情
56.      target.miai();//真正執行相親的方法,調用需要目標對象
57.      after();//相親之後要做的事情
58.  }
59.}

9.JAVA設計模式 - 迭代器設計模式

迭代器模式以順序方式訪問集合對象的元素 
迭代器模式代碼:

1.interface Iterator {
2.  public boolean hasNext();
3.  public Object next();
4.}
5.class LetterBag {
6.  public String names[] = {"R" , "J" ,"A" , "L"};
7.  public Iterator getIterator() {
8.     return new NameIterator();
9.  }
10.  class NameIterator implements Iterator {
11.     int index;
12.     @Override
13.     public boolean hasNext() {
14.        if(index < names.length){
15.           return true;
16.        }
17.        return false;
18.     }
19.     @Override
20.     public Object next() {
21.        if(this.hasNext()){
22.           return names[index++];
23.        }
24.        return null;
25.     }    
26.  }
27.}
28.public class Main {
29.  public static void main(String[] args) {
30.     LetterBag bag = new LetterBag();
31.     for(Iterator iter = bag.getIterator(); iter.hasNext();){
32.        String name = (String)iter.next();
33.        System.out.println("Name : " + name);
34.     }   
35.  }
36.}

迭代器模式的優點: 
簡化了遍歷方式,對於對象集合的遍歷,還是比較麻煩的,對於數組或者有序列表,可以通過下座標來取得,但用戶需要在對集合瞭解很清楚的前提下,自行遍歷對象,但是對於hash表來說,用戶遍歷起來就比較麻煩了,而引入了迭代器方法後,用戶用起來就簡單的多了,可以提供多種遍歷方式,比如說對有序列表,我們可以根據需要提供正序遍歷,倒序遍歷兩種迭代器,用戶用起來只需要得到我們實現好的迭代器,就可以方便的對集合進行遍歷了,封裝性良好,用戶只需要得到迭代器就可以遍歷,而對於遍歷算法則不用去關心 
迭代器模式的缺點: 
對於比較簡單的遍歷(像數組或者有序列表),使用迭代器方式遍歷較爲繁瑣,像ArrayList,寧可願意使用for循環和get方法來遍歷集合

10.JAVA設計模式 - 生產者與消費者設計模式

生產者與消費者模式代碼:

1.package cn.sc;
2./**
3.*生產者與消費者應用案例
4.*sleep與wait區別
5.*sleep讓當前的線程進入休眠狀態,讓出cpu,讓其他線程執行
6.*如果用同步的話,有對象鎖的時候,是不會釋放的,只能等待此線程使用完,纔可以使用
7.*wait會釋放對象鎖,必須等待其他線程喚醒
8.*@author JEEP-711
9.*
10.*/
11.public class ScXf {
12.  public static void main(String[] args) {
13.      Phones p = new Phones(null, null);//創建Phones對象
14.      PhoneSc s = new PhoneSc(p);//創建PhoneSc對象 
15.      PhoneXf x = new PhoneXf(p);//創建PhoneXf對象
16.      new Thread(s).start();//啓動生產者線程
17.      new Thread(x).start();//啓動消費者線程
18.   }
19.}
20.
21./**
22.* 手機生產者,單獨的生產者,實現Runnable接口
23.* @author JEEP-711
24.*
25.*/
26.class PhoneSc implements Runnable{
27.  private Phones phones;
28.  public PhoneSc(Phones phones){
29.      this.phones = phones;
30.  }
31.  @Override
32.  public void run() {
33.      //不斷地生產20份,生產的過程
34.      for (int i = 0; i < 50; i++) {
35.          if(i%2==0){
36.              phones.set("金立手機", "金立手機,中國造!");
37.          }else{
38.              phones.set("小米手機", "小米手機,爲發燒而生!");
39.          }
40.      }
41.   }
42.}
43.
44./**
45. *手機消費者,顧客
46.*@author JEEP-711
47.*
48.*/
49.class PhoneXf implements Runnable{
50.  private Phones phones;
51.  public PhoneXf(Phones phones){
52.      this.phones = phones;
53.  }
54.  @Override
55.  public void run() {
56.      for (int i = 0; i < 50; i++) {
57.          phones.get();//調用消費產品方法
58.      }
59.   }  
60.}
61.
62./**
63.*產品的對象,生產的手機
64.*@author JEEP-711
65.*
66.*/
67.class Phones{
68.  @Override
69.  public String toString() {
70.      return "Phones [name=" + name + ", content=" + content + "]";
71.  }
72.  private String name;
73.  private String content;
74.  /**true表示可以生產,false表示可以消費
75.*作爲標記,如何flag等於true表示可以生產,如何flag等於false表示不可生產
76.*如果flag等於false表示可以消費狀態,可以取走,flag等於true表示不能取走
77.*解決重複值得問題
78.*/
79.  private boolean flag = true;//表示可以生產,false表示可以消費
80.  //構造方法
81.  public Phones(String name, String content) {
82.      super();
83.      this.name = name;
84.      this.content = content;
85.  }
86.  //取得名稱方法
87.  public String getName() {
88.      return name;
89.  }
90.  //設置名稱方法
91.  public void setName(String name) {
92.      this.name = name;
93.  }
94.  //取得內容方法
95.  public String getContent() {
96.      return content;
97.  }
98.  //設置內容方法
99.  public void setContent(String content) {
100.      this.content = content;
101.  }   
102.
103.  /**
104.   *通過同步,解決了取值錯誤問題
105.   *@param name
106.   *@param content
107.   */
108.  //生產製造同步方法
109.  public synchronized void set(String name, String content){
110.      if(!flag){
111.          try {
112.          //調用該方法,當前線程進入等待池等待狀態,沒有指定時間,
113.          //需要其他線程喚醒,釋放對象鎖,讓出cpu
114.              this.wait();
115.          } catch (InterruptedException e) {
116.              e.printStackTrace();
117.          }
118.      }
119.      this.setName(name);
120.      try {
121.          Thread.sleep(300);
122.      } catch (InterruptedException e) {
123.          e.printStackTrace();
124.      }
125.      this.setContent(content);
126.      flag = false;//表示可以消費,取走
127.      this.notify();//喚醒在該監視器上的一個線程
128.  }   
129.
130.  //消費產品同步取值方法
131.  public synchronized void get(){
132.      if(flag){
133.          try {
134.              //調用該方法,當前線程進入等待池等待狀態,沒有指定時間,
135.              //需要其他線程喚醒,釋放對象鎖,讓出cpu
136.              this.wait();
137.          } catch (InterruptedException e) {
138.              e.printStackTrace();
139.          }
140.      }
141.      try {
142.          Thread.sleep(300);
143.      } catch (InterruptedException e) {
144.          e.printStackTrace();
145.      }
146.      System.out.println(this.getName()+":"+this.getContent());
147.      flag = true;
148.      this.notify();
149.   }  
150.}

初學(面向對象近階段) Ⅳ 難點: ★★★★★★★

希望每一篇文章都能夠對讀者們提供幫助與提升,這乃是每一位筆者的初衷


感謝您的閱讀 歡迎您的留言與建議


發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章