前言:面向對象設計的幾大原則?java
1》針對接口編程,而不是針對實現編程web
2》優先使用對象組合,而不是類繼承數據庫
1.只根據抽象類中定義的接口來操縱對象有如下兩個好處?編程
1)客戶無須知道他們使用對象的特定類型,只需對象有客戶所指望的接口設計模式
2)客戶無須知道他們使用的對象是用什麼類來實現的,他們只須知道定義接口的抽象類安全
這將極大地減小子系統實現之間的相互依賴關係,也產生了可複用的面向對象設計的以下原則:服務器
針對接口編程,而不是針對實現編程架構
2.繼承和組合的比較?框架
繼承:jsp
類繼承是在編譯時刻靜態定義的,且可直接使用,由於程序設計語言支持類繼承,能夠較方便的改變被複用的實現。
1)繼承在編譯時刻就定義了,因此沒法再運行時刻改變從父類繼承的實現,而且父類一般至少定義了部分子類的具體表示。由於繼承對子類揭示了其父類的實現細節,常被認爲
「破壞了封裝性」,子類中的實現與它的父類有如此緊密的依賴關係,以致於父類實現中的任何變化必然致使子類發生變化。
2)若是繼承下來的實現不適合解決新的問題,則父類必須重寫或被其餘更適合的類替換,這種依賴關係限制了靈活性並最終限制複用性。一個方法:只繼承抽象類(提供較少的實現)
組合:
1)對象組合是經過得到對其餘對象的引用而在運行時刻動態定義的。組合要求對象遵照彼此的接口約定,進而要求更仔細的定義接口,而這些接口並不會妨礙你將一個對象和其餘對象
一塊兒使用。對象只能經過接口來訪問,並不破壞封裝性;只要類型一致,運行時刻還能夠用一個對象來替代另外一個對象;更進一步,由於對象的實現是基於接口編寫的,因此不多依賴
2)優先使用對象組合有助於你保持每一個類被封裝,並被集中在單個任務上。這樣的類和類繼承層次會保持較小的規模,另外一方面,基於對象組合的設計會有更多的對象(而有較少的類)
且系統的行爲將依賴於對象間的關係而不是被定義在某個類中
導出咱們的面向對象設計的第二個原則:
優先使用對象組合,而不是類繼承
3.模式與框架的區分?
1)設計模式比框架更抽象
框架可以用代碼表示,而設計模式只有其實例才能表示爲代碼。框架的威力在於它們可以使用程序設計語言寫出來,它們不只能被學習,也能被直接執行和複用
2)設計模式是比框架更小的體系結構元素
一個典型的框架包含了多個設計模式,而反之絕非如此
3)框架比設計模式更加特例化
框架老是針對一個特定的應用領域。一個圖形編輯器框架可能被用於一個工廠模擬,但它不會被認錯爲是一個模擬框架
框架變得愈來愈廣泛和重要。它們是面向休息系統得到最大複用的方式。較大的面對對象將會由多層彼此合做的框架組成。應用的大部分設計和代碼未來自於他所使用的框架
第二章Java程序設計中最基本的設計模式(23種)
設計模式有什麼:描述一個設計模式,一般包含以下四個部分:
模式名稱:就是爲每個設計模式取個名字,好記憶交流
壞境和問題:描述在什麼場景下,出現什麼樣的特定的問題
解決方案:描述如何解決問題
效果:描述模式可能帶來的問題,或者使用過程當中須要權衡的問題
1、單例模式
問題:採用什麼方法來控制建立類實例,而後確保在任何給定的時間只建立一個類實例
方案:Singleton模式主要做用是保證在Java程序中,一個類只有一個實例存在。不少時候,好比創建目錄,數據庫鏈接都須要這樣的單線程操做。
Singleton可以被狀態化,這樣,多個單態類在一塊兒就能夠做爲一個狀態倉庫同樣向外提供服務 例子:論壇中的帖子計數器--synchronize的安全自動加一
Singleton也可以被無狀態化。好處在於能夠節省內存,由於它限制了實例的個數,有利於Java垃圾回收
使用示例:通常Singleton模式一般有兩種形式:
one:較安全些
public class Singleton{
private Singleton(){}
//在本身內部定義本身的一個實例,是否是很奇怪?
//注意這是private只供內部調用
private static Singleton instance = new Singleton();
//這裏提供了一個供外部訪問本class的靜態方法,能夠直接訪問
public static Singleton getInsatnce(){
return instance;
}
}
two:
public class Singleton{
//第一次調用初始Singleton,之後就不用再生成了
private static Singleton instance = null;
public static synchronized Singleton getInstance(){
//這個方法比上面的有所改進,不用每次都進行生成對象,只是第一次
//使用時產生實例,提升了效率
if(instance==null)
instance = new Singleton();
return instance;
}
}
使用Singleton注意事項:(真正使用好,須要對Java的類線程內存等概念有至關的瞭解)
1.有時在某些狀況下,使用Singleton並不能達到效果,在有多個Singleton對象同時被不一樣的類裝入器裝載;在EJB這樣的分佈式系統中使用也要注意這種狀況,
由於EJB是跨服務器的,跨JVM的
分析說明:在EJB中,Singleton模式會失去做用,SUN公司的寵物店源碼中ServiceLocator才分爲兩種,一種是面向WEB的,一種是面向EJB服務的
2、工廠模式---標準的建立對象的方法
問題:定義一個用於建立對象的接口,讓子類決定實例化哪個類。工廠模式使一個類的實例化延遲到其子類
方案:工廠模式是一種建立性模式,它定義了一個建立對象的接口,可是卻讓子類來決定具體實例化哪個類。當一個類沒法預料要建立哪個類對象或是一個類
須要由子類來指定建立的對象時咱們就須要用到工廠模式了。簡單來講工廠模式能夠根據不一樣的條件產生不一樣的實例(相同的類型),工廠模式把這些實例的
具體過程封裝起來了,簡化了客戶端的應用,也改善了程序的擴展性,使得未來能夠作最小的改動就能夠加入新的待建立的類
爲什麼如此經常使用?
由於工廠模式就至關於建立實例對象的new,咱們常常要根據類class生成實例對象,如A a = new A()工廠模式也是用來建立實例對象的,因此之後new時要多個心眼
是否能夠考慮使用工廠模式,雖然這樣作,可能多作一些工做,可是會給你的系統帶來更大的可擴展性和儘可能少的修改量
案例:
咱們以類Sample爲例,咱們要建立Sample的實例對象:Sample sample = new Sample();但是實際狀況是一般咱們都要在建立sample實例時作點初始化的工做,好比:
賦值,查詢數據庫等
首先想到的就是使用Sample的構造函數,這樣生成實例就寫成:Sample sample = new Sample(參數);建立實例化時所做的初始化工做不像賦值那麼簡單,多是很長
的代碼寫入構造函數中,那麼你的代碼將會很難看(爲什麼?)-----初始化工做若是是很長的一段代碼,說明要作的工做不少,將不少工做裝入一個方法中,
至關於將不少的雞蛋放在一個籃子裏,是很危險的,這也有悖於Java面向對象的原則,面向對象的封裝和分派告訴咱們,儘可能將長的代碼分派切割成每段,
將每段再封裝起來(減小段與段之間耦合聯繫性),之後若是須要修改,只要更改每段,不會再發生牽一動百的事情
工廠模式中有:工廠方法(Factory Method),抽象工廠(Abstract Factory),這兩個模式區別在於須要建立對象的複雜程度上
@1.工廠方法:
創建一個專門生產Sample實例的工廠:
public class Factory{
public static Sample creator(int which){
//getClass產生Sample 通常可以使用動態類裝載入類
if(which==1)
return new SampleA();
else if(which==2)
return new SampleB();
}
}
那麼在你的程序中,若是要實例化Sample,就使用 Sample sampleA = Factory.creator(1);
這樣在整個涉及到Sample的具體子類,達到封裝的效果,也就減小錯誤修改的機會 通俗來說:即具體的事情作得越多,越容易犯錯
使用工廠方法要注意幾個角色,首先你要定義產品接口,如上面的Sample,產品接口下有接口的實現類,如SampleA,其次要有一個factory類,用來生成產品Sample
進一步稍微複雜點,就是在工廠類上進行擴展,工廠類也有繼承它的實現類concreateFactory了
@2.抽象工廠
若是咱們建立對象的方法變得複雜了,如上面工廠方法中是建立一個對象Sample,若是咱們還有新的產品接口Sample2,假設Sample和Sample2均有兩個concrete類SampleA(B)
那麼,咱們就將上例中的Factory擴展成抽象工廠:
public abstract class Factory{
public abstract Sample creator();
public abstract Sample2 creator(String name);
}
public class SimpleFactoy extends Factory{
public Sample creator(){
....................
return new SampleA();
}
public Sample2 creator(String name){
....................
return new Sample2A();
}
}
public class BombFactory extends Factory{
public Sample creator(){
..........
return new SampleB();
}
public Sample2 creator(String name){
....................
return new Sample2B();
}
}
從上面看到兩個工廠各自生產出一套Sample和Sample2,也許你會產生疑問,爲何我不可使用兩個工廠方法來分別生產Sample和Sample2?
抽象工廠還有另一個關鍵要點,是由於SimpleFactory內,生產Sample和生產Sample2的方法之間有必定聯繫,因此纔要將這兩個方法捆綁在一個類中。
@3、值對象模式--成爲不一樣層或不一樣模塊之間數據交換的標準方法,體現的是數據的封裝,也有利於對象的複用。
問題:應用程序客戶端須要與企業Bean之間交換數據,程序間交換數據---基於客戶須要與EJB之間大量滴交換數據的狀況,具體說來,在J2EE平臺中,應用程序一般將服務器端
的程序組件實現爲會話bean和實體bean,而這些組件的部分方法則須要將數據返回給客戶;這種狀況下,一般一個用戶會重複調用相關方法屢次,直到它獲得相關信息
注意的是:多數狀況這些方法的調用目的是爲了取得單一的信息,例如用戶名或者用戶地址等
顯而易見,在J2EE平臺上,這種調用基本上都是遠程的,也就是說,用戶屢次調用相應的方法會給Web帶來極大的負擔,即便用戶和EJB容器加載相同的JVM、OS和計算機
運行EJB程序,因爲方法調用被缺省地認爲是遠程任務,因此這種問題依然存在
方案:值對象(value object)模式經過減小分佈式通訊的消息而促進數據的交換,一般這裏說指的通訊是在web層和EJB層之間。在一個遠程調用中,一個單一值對象能夠被用來
取出一系列相關數據並提供給客戶。
當EJB使用值對象的時候,用戶能夠經過僅僅一次方法調用來取得整個對象,而不是使用屢次方法調用以獲得對象中每一個域的數值;因爲值對象是經過值傳遞來交送給用戶
的,因此對於該值的調用或取值都是本地調用,而不是遠程方法調用。需注意:這個值對象必須對應於每一個屬性的訪問方法,或者將全部屬性都設爲公共的
例子:
假設某名爲project的業務對象被模擬或者實現爲一個實體bean,當客戶端調用值對象的getProjectData()方法時,該project實體bean須要經過該值對象向客戶端發送數據
public class ProjectVO implements java.io.Serializable{
private String projectId;
private String projectName;
private String managerId;
private String customerId;
private Data startDate;
private Date endDate;
private boolean started;
private boolean completed;
private boolean accepted;
................
//Value object constructors
如下就是具體的每個get和set方法
}
@4、DAO模式
問題;目前大部分的J2EE應用程序都須要在必定程度上使用可持久的數據,而實現持久性數據的方法因應用程序不一樣而異,且訪問不一樣存儲格式數據的應用程序接口也有顯著的差異
當程序組件,即實體bean、會話bean或servlet、jsp等須要訪問數據源時,它們會使用正確的應用程序接口來獲得鏈接並管理數據源,但這樣也會形成這些組件與數據程序源
之間的依賴關係,從而使得應用程序很難從一個數據存儲實體移植到另外一個數據存儲實體中去;當數據源的物理實現變化的時候,應用程序也相應地加以改變
如何對存儲層之外的模塊屏蔽這些複雜性,以提供統一的調用存儲實現?
方案:
(1)業務對象:表示數據的用戶,它須要對於數據的訪問,一個業務對象能夠用會話bean、實體bean或是其餘Java程序來實現
(2)數據訪問對象:是這種模式的主題,它提供了底層數據訪問的對象,並將其提供給業務對象以使得後者可以透明地訪問數據源;同時業務對象也將數據的加載和存儲
操做移交給數據訪問對象處理。
(3)數據源:這裏指的是數據源的物理實現,這個數據源能夠是一個數據庫,包括關係型數據庫、面向對象數據庫或文件系統
(4)值對象:指的是數據載體,數據訪問對象可使用值對象來向用戶返回數據,而數據訪問對象一樣能夠從用戶那裏獲得值對象來對數據源中的數據進行更新
應用實例:
抽象的DAOFactory類
public abstract class DAOFactory{
public static final int CLOUDSCAPE=1;
public static final int ORACLE = 2;
public static final int SYBASE = 3;
public abstract CustomerDAO getCustomerDAO();
public abstract AccountDAO getAccountAO();
public abstract OrderDAO getOrderDAO();
....................
public static DAOFactory getDAOFactory(int whichFactory){
switch(whichFactory){
case CLOUDSCAPE:
return new CloudscapeDAOFactory();
case ORACLE:
return new OracleDAOFactory();
case SYBASE:
return new SybaseDAOFactory();
......
default:
return null;
}
}
}
具體的DAOFactory的實現:
public class CloudscapeDAOFactory extends DAOFactory{
public abstract CustomerDAO getCustomerDAO(){
return new CloudscapeCustomerDAO();
}
public abstract AccountDAO getAccountAO(){
return new CloudscapeAccountDAO();
}
public abstract OrderDAO getOrderDAO(){
return new CloudscapeOrderDAO();
}
}
4.3:Customer的基本DAO接口
public interface CustomerDAO{
public int insertCustomer(.....);
public boolean deleteCustomer(....);
public Customer findCustomer(....);
........
}
4.4.Customer的Cloudscape DAO實現
public class CloudscapeCustomerDAO implements CustomerDAO{
public CloudscapeCustomerDAO(){初始化;}
public int insertCustomer(.....){....};
public boolean deleteCustomer(....){.....};
public Customer findCustomer(....){......};
}
4.5:Customer值對象
public class Customer implements java.io.Serializable{
int CustomerNumber;
Stirng name;
String streetAddress;
String city;
.......//getter and setter methods
}
4.6:使用DAO和DAO工廠-----客戶端代碼
//建立一個DAO工廠
DAOFactory cloudscapeFactory = DAOFactory.getDAOFactory(DAOFactory.DAOCLOUDSCAPE);
//建立一個DAO
CustomerDAO custDAO = cloudscapeFactory.getCustomerDAO();
//建立一個用戶
int newCustNo = custDAO.insertCustomer(.....);
//查找到一個用戶
Customer cust = custDAO.findCustomer(.....);
//設置參數
cust.setAddress(...);
cust.setEmial(...);
//更新
custDAO.updateCustomer(cust);
..................等等其餘操做
第三章 Java程序設計和模式應用
前面咱們講到了兩個面向對象的設計原則:
一是針對接口編程,而不是針對實現編程
二是優先使用對象組合,而不是類繼承
下面咱們講學習其餘的常見的面向對象的設計原則:
1.開放-封閉法則(OCP)即對新增開放,對修改封閉。並且應儘可能作到不用修改模塊的源代碼,就能更改模塊的行爲。
認爲咱們應該設計出永遠也不須要改變的模塊,咱們能夠添加新代碼來擴展系統的行爲。咱們不能對已有的代碼進行修改
符合OCP的模塊需知足兩個標準:
1)可擴展,即「對擴展是開放的」,---模塊的行爲能夠被擴展,以知足新的需求
2)不可更改,即「對更改是封閉的」----模塊的源代碼是不容許進行改動的
如何去作呢?
1)抽象 2)多態 3)繼承 4)接口
一個軟件系統的全部模塊不可能都知足OCP,可是咱們應該努力最小化這些不知足OCP的模塊數量
開放-封閉法則是OO設計的真正核心
符合該法則便意味着最高等級的複用性和可維護性
2.依賴性倒置原則:
就是依賴抽象而不要依賴具體的實現
3.接口隔離原則:
就是不要使用通用的接口,而是爲不一樣的用戶使用不一樣的接口
4.替換原則:
即子類應當能夠替換父類並出如今父類可以出現的任何地方
類設計的基本經驗:
類要單一
增強內聚,鬆散耦合
好的封裝性
類的粒度要合理
實現類不能依賴它的使用類
應考慮靈活性,也就是可配置、可維護
要考慮性能,考慮可伸縮性
要考慮從此可能的變化,也就是可擴展性
要考慮合理的複用
要合理的考慮接口和抽象類的使用
儘可能減小類與協做類的交互次數和交互信息的量
父類不該知道子類的信息,子類必須知道父類的信息
更多的使用類的組合,而不是繼承
訪問對象必須經過接口,不能繞過接口直接訪問
分層:最典型的三層架構,表現層--》邏輯層--》數據層
表現層功能:展現數據、人機交互、收集參數調用邏輯層
邏輯層功能:進行數據的邏輯校驗、進行邏輯判斷、實現業務功能、處理相關功能、處理後續流程、組織數據返回給表現層
數據層功能:實現數據持久化、實現對象和持久化數據的雙向映射
層間交互的基本原則:
1.表現層調用邏輯層,邏輯層調用數據層,不可反過來!!
2.層間交互也應該經過接口進行調用,以確保各層的實現獨立變化