3月24日——培訓第88天

 用例、類、時序、順序這幾個圖是比較重要的
用例圖確定需求,順序圖確定對象間的協作,類圖確定系統的結構(敏捷建模)

JMS的兩種機制:隊列機制(Queue)和主題機制(Topic)
隊列機制:我發一個,對方取一個
主題機制:我發一個主題,發給所有訂閱了這個主題的人

Sender發消息給服務器,服務器發現這個消息後通知receiver,receiver知道後就來
服務器上取這個消息了。

JMS是異步的,不是同步的。

====================================================================

在面向對象設計的演化過程中,最重要的事情就是設計模式的誕生。

1995年出版的《Design Patterns,Elements of Reusable Object-Oriented Software》
被認爲是設計模式發展的里程碑,已經成爲軟件設計與開發人員的必修課程。

這本書的作者一共有四個人,通常稱他們是GOF(Gang Of Four)

國內有一個名叫顏宏的人寫了一本叫做《java與模式》的書,非常的厚,但是好像廢話比較多。

Erich Gamma(瑞士國際面向對象技術軟件中心的技術主管)
還是JUnit開源框架的作者之一,同時還是著名的Eclipse的主要奠基人

設計模式提倡的兩大核心思想(面向接口,而非面向具體的實現;對象組合,提倡優先使用對象組合,而非繼承)
繼承被成爲白箱複用,組合被稱爲黑箱複用。

23種設計模式依據兩種準則對他們進行分類:目的準則、範圍準則

目的準則:創建型模式(比如單例模式)、結構型模式(比如adaptor適配器模式)、行爲模式(觀察者模式)
範圍準則:類模式(繼承方式)、對象模式(對象組合)

目的準則以模式功能爲分類標準。
創建型模式將對象的部分創建工作延遲到子類,而創建型對象模式則將它延遲到另一個對象中。

結構型類模式使用繼承機制

-------------------------------------------------------

創建型模式(取代直接new對象的方式,這種方式導致這個類緊耦合了,爲了類的實現和系統鬆
耦合,所以出現創建型模式)
單例模式、原型模式、工廠方法、抽象工廠、生成器

單例模式(Singleton):保證一個類只有一個實例
原型模式(Prototype):用原型實例指定創建對象的種類,並且通過拷貝這些原型創建新的對象。
工廠方法(Factory Method):提供一個用於創建對象的接口,讓子類決定實例化哪一個類
抽象工廠(Abstract Factory):提供一個創建一系列相關或者相互依賴對象的接口,而無需指定
       他們具體的類。
生成器(Builder)
---------------------------------------------
單例模式就是通過把構造方法弄成私有來保證客戶無法任意創建對象。對象的單例是相對於的是java的
類加載器來說的。

聲明時初始化靜態單例變量
類加載時初始化靜態單例變量(靜態塊)
在得到實例的方法中初始化靜態單例變量

//惰性單例模式
public class Singleton
{
 private static Singleton instance ;
 private Singleton()
 {}

 public static Singleton getInstance()
 {
  if(instance==null)
  {
   instance = new Singleton();
  }
  return instance ;
 }
};

//如果是非惰性呢?

public class Singleton
{
 //private static Singleton instance = new Singleton();

 static
 {
  private static Singleton instance = new Singleton();
 }
 private Singleton()
 {}

 public static Singleton getInstance()
 {  
  return instance ;
 }
};

初始化,構造方法外面的聲明或是塊中的聲明誰在前面誰先初始化,
注意構造函數的初始化是在最後進行的。

常量不一定要在聲明的時候賦值,但是它必須在構造函數之前賦值,且只能賦值一次。

僞單例模式:
相對線程單例(Hibernate中的ThreadLocal)、相對類加載器單例(BeanUtils和BeanUtilsBeans
就用到了這種單例模式)、相對特定上下文單例

線程單例保證在一個線程中只有一個實例,在java中可以通過ThreadLocal實現


Prototype模式:
將一個對象原封不動的複製給另外一個對象而且又不需要直接創建對象。
不創建對象,而通過已經有的對象進行復制,這個已經有的對象通常稱爲原型。

深拷貝和淺拷貝:
java語言已經將原型模式固化到對象中了,因此可以通過Object.clone以及Cloneable
接口配合實現。

--------------------------------------
Factory Method模式:
類A要創建類B,但是不知道類B的類型是什麼……

工廠模式:工廠模式是一種經常被使用到的模式,根據工廠模式實現的類可以根據提供的數據
生成一組類中某一個類的實例,通常這一組類有一個公共的抽象父類並且實現了相同的方法,
但是這些方法針對不同的數據進行了不同的操作。首先需要定義一個基類,該類的子類通過不
同的方法實現了基類中的方法。然後需要定義一個工廠類,工廠類可以根據條件生成不同的子
類實例。當得到子類的實例後,開發人員可以調用基類中的方法而不必考慮到底返回的是哪一
個子類的實例。

植物都會開花結果,但是植物本身是一個抽象的概念,只有具體的植物(桃樹、梨樹等等)
纔會結出具體的果實(Fruit),將植物產果的邏輯延遲到具體的植株上去。

//使用抽象方法或接口的形式將對象的實現延遲到具體子類中去。
public abstract class Plant
{
 public abstract Fruit createFruit();

 public void grow()
 {
  System.out.println("開花");
  createFruit().info();
 }
}

public abstract class Fruit
{
 public abstract void info() ;

}


public class PeachPlant extends Plant
{
 public Fruit createFruit()
 {
  return new PeachFruit();
 }

}


public class PeachFruit extends Fruit
{
 public void info()
 {
  System.out.println("桃樹結果");
 }
}


public class Demo
{
 public static void main(String[] args)
 {
  Plant peach = new PeachPlant();
  peach.grow();
 }
}


Collectin的iterator方法返回Iterator可認爲是工廠方法的一種
典型應用,Hibernate中的SessionFactory.openSession,
Spring中的BeanFactory.getBean,FactoryBean.getObject
都是

----------------------------------------

Abstract Factory模式:
一組對象間有相互依賴和協作的關係,稱爲一個產品系。如何保證它們能夠正確的
搭配工作?

抽象的CPU、由它繼承兩個:一個是筆記本的CPU、一個臺式機的CPU
同理,主板、內存、硬盤等也是類似的道理

抽象工廠下面有兩個具體的工廠,一個工廠具體生產筆記本、一個工廠具體生產臺式機。

要有一個工廠的體系,還要有一個產品的體系,用工廠來製造產品

先做一個抽象的工廠ComputerFactory
public abstract class ComputerFactory
{
 public abstract Mainboard createMainboard();
 public abstract HardDisk createHardDisk();
}

具體的工廠NotebookComputerFactory
public class NotebookComputerFactory extends ComputerFactory
{
 public HardDisk createHardDisk()
 {
  return new NoteHardDisk();
 }

 public HardDisk createHardDisk()
 {
  return new NoteMainBoard();
 }
}

定義抽象產品系:Mainboard、Harddisk(主板和硬盤)
public abstract class Mainboard
{
 public abstract void addHardDisk(HardDisk hd) ;
}

//筆記本的主板
public class NoteMainboard extends Mainboard
{
 public void addHardDisk(HardDisk hd)
 {
  System.out.println("在筆記本電腦的主板上加入了筆記本的硬盤!");
 }
}

//筆記本的硬盤
public class NoteHardDisk extends HardDisk
{

}

//只要給了生產筆記本的工廠,那麼該工廠生產的部件一定是筆記本的部件,
//就是這個意思。
ComputerFactory cf = new NotebookComputerFactory();
Mainboard mb = cf.createMainboard();
HardDisk hd = cf.createHardDisk();
mb.addHardDisk(hd);

在java中抽象工廠的典型應用就是JMS(隊列機制和主題機制)
發送者和接收者本身就是兩種抽象的產品系,每種產品系都有兩套機制,一套
是隊列機制,一套就是主題機制。

只有隊列機制的發送者才能和隊列機制的接收者通信。

在j2ee1.4的api中的javax.jms包裏面可以看到JMS是使用了抽象工廠的模式:

MessageProducer接口下面有QueueSender和TopicPublisher兩個子類
ConnectionFactory下面有兩個具體的工廠:QueueConnectionFactory和
TopicConnectionFactory分別生產隊列機制和主題機制的產品(接收者和發送者)

-----------------------------------
抽象工廠與工廠方法到底什麼區別?

二者之間聯繫大於區別,抽象工廠一般是通過工廠方法來實現的。
二者區別並不明顯,工廠方法只是抽象工廠模式的一種實現方法而已。抽象工廠模式
的實現也可以使用原型模式(抽象工廠強調工廠之間的協作)

工廠方法實現抽象工廠模式:必須爲每個產品系都做出一個新的工廠,而且無法在已有的產品系中
增加新的產品。

使用原型模式實現抽象工廠不能保證生產出來的產品相互之間的協調。

public class ComputerFactory
{
 public Mainboard createMainboard(Mainboard mb) throws Exception
 {
  return (Mainboard)mb.clone();
 }

 public HardDisk createHardDisk(HardDisk hd) throws Exception
 {
  return (HardDisk)hd.clone();
 }
}

public abstract class HardDisk implements Cloneable
{
 public Object clone()
 {
  return super.clone();
 }
}

public abstract class Mainboard implements Cloneable
{
 public Object clone()
 {
  return super.clone();
 }
}

main函數:

ComputerFactory cf = new NotebookComputerFactory();
Mainboard mb = cf.createMainboard(new NoteMainboard());
HardDisk hd = cf.createHardDisk(new NoteHardDisk());
-------------------------------------------------------

創建型模式的最後一種模式:Builder模式。

如果構造對象的過程比較複雜,並且可能構造的對象也是不可預測的,希望
將構造過程獨立出來,變得可插拔,應該如何實現?

一家綜合餐館,既可以做中餐,又可以做西餐,編寫程序使得餐館與所做的食品
鬆耦合,能夠讓餐館隨時加入其他風格的食品,比如日本料理。

Restaurant這個類裏面有一系列的班子(廚房),這些廚房是可以替換的,
可以隨時替換。

public class Restaurant
{
 private Kitchen kit ; 
 private ArrayList res ;

 public Restaurant()
 {
  res = new ArrayList() ;
  res.add("rice");
  res.add("meat");
  res.add("dish");
 }
 public void setKit(Kitchen kit)
 {
  this.kit = kit ;
 }

 public Food makeFood()
 {
  return kit.getFood(res) ;
 }
}

public abstract class Kitchen
{
 public abstract Rice buildRice();
 public abstract Dish buildDish();
 public abstract Meat buildMeat();

 public abstract Food getFood(ArrayList res) ;
}


public ChineseFoodKitchen extends Kitchen
{
 public  Rice buildRice()
 {
  return new Rice() ;
 }
 public  Dish buildDish()
 {
  return new Dish() ;
 }
 public  Meat buildMeat()
 {
  return null ;
 }

 public  Food getFood(ArrayList res)
 {
  ChineseFood food = new ChineseFood();
  
  return null ;
 }
}

public class Dish
{

}

public class Rice
{

}

public class Meat
{

}

public class Food
{
 private Rice rice ;
 private Dish dish ;
 //getter和setter方法略
}


--------------------------------------------
寫簡單點來說就是:

Restaurant r = new Restaurant();
Kitchen k1 = new ChineseFoodKitchen() ;
r.setKit(k1);
System.out.println(r.makeFood().toString());

Kitchen k2 = new WesternFoodKitchen() ;
r.setKit(k2);
System.out.println(r.makeFood().toString());

通過不同的廚房來構築飯店,只需要飯店中的setter方法改變廚房即可
改變makeFood的具體行爲(makeFood方法通過調用具體廚房的getFood
方法決定飯菜的種類)。

在ConvertUtils中對Builder模式應用的很典型。

======================================================
上面是五種創建型模式(單例模式、原型模式、工廠方法、抽象工廠、創建模式)……
接下來是結構型模式

結構型模式:如何組合類和對象以獲得更大的結構,採用繼承機制來組合接口或實現。

Adapter、Bridge、Composite、Decorator、Facade、Flyweight、Proxy
適配器、橋接、組成、裝飾、外觀、享元、代理
-----------------------------------------------------
Adapter:如何將一個類的接口轉換成客戶希望的另外一個接口,使得原本由於接口
不兼容而不能在一起工作的那些類可以一起工作。

比如:老系統使用JDK較早版本,因此只能夠讀取Enumeration類型的集合;而
新系統由於使用了新版本JDK,所以提供的集合都是List類型的。現在在不更改新、
老系統的情況下,如何讓老系統能夠順利讀取新系統提供的集合?

也就是提供的數據是List類型,但是舊的系統只能夠接收Enumeration類型
如何把List類型包成Enumeration類型傳給新系統?

可以考慮建立一個Adapter繼承Enumeration,當然這個Adapter肯定得重寫
Enumeration裏面的nextElement方法和hasMoreElement方法,同時Adapter
裏面再組合一個List就可以了。(通過構造器)也就是對象組合方式

之所以要組合一個List,是要把新版本的這個List裏面的對應方法拿出的數據
轉到Enumeration中的對應方法中去,從而將這個繼承了Enumeration的Adapter
能夠順利的傳到老系統中去 。


還有一種多繼承的方式。(java中只能使用接口的方式來做了,在上面的例子
裏面就是同時繼承List和Enumeration)

在實際中的應用場合:
AWT中的監聽器
IO中的InputStreamReader和OutputStreamWriter

----------------------------------------------------------
Bridge模式:
抽象與具體是不是一定要通過繼承來實現?使用繼承會有緊耦合的問題
抽象與具體通過繼承實現的時候,將抽象與具體緊密耦合,抽象層面的每一次擴充都會
導致具體層面的擴充。

手機可以傳遞兩種信息、語言信號Phone和文本信號Text,同時,手機通信有GSM和
CDMA兩種通信網絡。現在要建立信號(Signal)的類體系,能夠描述GSM的語言信號、
GSM文本信號、CDMA語言信號,CDMA文本信號,如果現在還需要傳遞視頻信號Video
,那麼又該如何實現?

將抽象層和具體實現層隔離開,
分成信號類型和網絡類型兩個體系:
public abstract class Signal
{
 
 protected Network net ;

 public void setNetwork(Network net)
 {
  this.net = net ;
 }

 public abstract String getCode() ;
}

public abstract class Network
{
 public abstract void decode();
 public abstract String getNetType() ;
}

public class TextSignal extends Signal
{
 public String getCode()
 {
  return "使用"+net.getNetType()+"的文本信號" ;
 }
}

public class PhoneSignal extends Signal
{
 public String getCode()
 {
  return "使用" + net.getNetType() + "的語音信號!" ;
 }
}

public class GSMNet extends Network
{
 public void decode(){}

 public String getNetType()
 {
  return "GSM網絡" ;
 }
}

public class CDMANet extends Network
{
 public void decode(){}

 public String getNetType()
 {
  return "CDMA網絡" ;
 }
}

public static void main(String[] args)
{
 Signal s = new TextSignal() ;
 Network netFirst = new GSMNet() ;
 Network netSecond = new CDMANet() ;

 s.setNetwork(netFirst);
 System.out.println(s.getCode());
}

橋模式應用的場景:一種事物具有兩種特徵,而且這兩種特徵可以各自作爲獨立體系出現。
最主要是在兩個需要協作,又可以獨立成爲體系的對象之間使用橋模式。選擇主系類,並
使主系類中包含次系類的頂層實現。

橋模式的典型應用:JDBC中的Connection和Driver之間的關係、
Hibernate中的Query和Dialect之間的關係。

 

發佈了111 篇原創文章 · 獲贊 6 · 訪問量 18萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章