說明
借鑑的JDK中的優秀源碼來幫助自己理解設計模式,另外一方面還能幫助自己深入的瞭解JDK。類型中包含的模式可能不齊全,我只詳細的描述了一些相對重要的設計模式。
類之間的關係
設計模式主要是基於類之間的關係來設計的。先了解類之間的關係和表示形式是很有必要的。
繼承關係
實現關係
依賴關係
類A使用到了另一個類B,或者對象方法中返回B類對象
關聯關係
類A的成員變量是類B,體現的是兩個類之間語義級別的一種強依賴關係
聚合關係
聚合是關聯關係的一種特例,它體現的是整體與部分的關係,即has-a的關係。整體與部分可分。如公司與員工。
組合關係
組合也是關聯關係的一種特例,它體現的是一種contains-a的關係,這種關係比聚合更強。整體與部分是不可分的關係。如人體與心臟。
對象的四種生成方式
1.使用new來創建。
Object object=new Object();//此種方法將會調用類的構造函數。
2.java的反射機制
///////假設你已經創建了一個類Test
//方式一,使用Class類,會調用類的構造函數,方式一內部的實現還是調用方式二的getConstructor方法來實現的
Class class=Class.forName("包名.Test");
Test test1=(Test)class.newInstance();//創建了test對象,由object對象轉換爲test對象
//方式二使用Constructor,會調用類的構造函數
Constructor<Test>cons=Test.class.getConstructor();
Test test2=cons.newInstance();
3.clone方法
///////假設你已經創建了一個類Test,其中Test類需要實現Cloneable接口,複寫clone方法。具體怎麼複寫,需要看你是深複製還是淺複製.
Test test=new Test();//之前已經創建了一個對象.
Test test1=test.clone();//創建了一個新的對象,此時不在調用構造函數,並且test1指向的新堆的內存空間.
4.反序列化方法
///當我們序列化和反序列化一個對象,jvm會給我們創建一個單獨的對象。類需要實現序列化接口
ObjectInputStream in = new ObjectInputStream(new FileInputStream("test.obj"));
Test test= (Test) in.readObject();
創建型模式
提供了創建什麼(what),由誰來創建(who),以及何時(when)來創建
單例模式
目標:
向整個系統提供一個唯一的對象實例。
why-思考:
如何確保要生成的類的對象只有一個?當需要使用使用該對象時是使用時先生成還是創建該類的時候生成?如何確保多處同時需要訪問唯一對象時,怎麼確保原子性?
How-思考:
將構造方法私有化,並在內中方法生成對象,外部將不能生成對象了;需要查看具體的情況,看資源使用率和線程安全性,資源使用率高的是懶加載,線程安全性好的創建類時便生成對象;使用多線程間鎖的機制。
JDK中的示例:
//java.lang.Runtime類
public class Runtime {
private Runtime() {}//私有的構造方法
//Runtime類的私有靜態實例
private static Runtime currentRuntime = new Runtime();
//獲得靜態實例的唯一方法
public static Runtime getRuntime() {
return currentRuntime;
}
}
工廠三大類模式
包括靜態工廠、工廠模式、抽象工廠。工廠相關的模式主要包含要創建的對象類(產品類)和主導有創建功能的類(工廠類)。
目標:
*靜態工廠*,因爲要創建的類型較少,可根據類型進行創建對象,並且要將對象的實例化過程進行封裝,外部創建對象調用的方式更清晰。
*工廠模式*,因爲要創建的類型的對象較多,並且可能需要擴展對象的類型,讓子類去決定實例化那個對象。重點在如何抽取要創建的對象類的共同點上。
**抽象工廠**,因爲要創建的對象的包含的組別很多,不同的組包括不同的類型,爲創建一組相關或相互依賴的對象。重點在如何抽取要創建的對象類的共同點上和抽象化工廠類上。
why—思考:
*靜態工廠*,工廠類如何做到根據不同的參數類型,輸出不同的對象?
*工廠模式*,如果對象的參數類型過多,並且或者需要不定期擴展不同的對象時,工廠類該怎樣設計?
**抽象工廠**,要創建的對象是一組相關的或相互依賴,並且組內不同的對象類型可以不同,工廠模式又該怎麼設計?
How-思考:
*靜態工廠*,通過添加靜態生成對象的函數,根據不同的參數,使用不同的實例化對象的方法。
*工廠模式*,提取出要創建的不同類型的對象的公共方法並封裝成接口,在具體的對象中實現該接口。
**抽象工廠**,工廠模式的擴展,因爲組包含一組包含多個不同類型的對象。
JDK中的示例:
//////////////////////////靜態工廠java.lang.Class
//根據不同的類名來創建對象
public static Class<?> forName(String className)
throws ClassNotFoundException {
Class<?> caller = Reflection.getCallerClass();
return forName0(className, true, ClassLoader.getClassLoader(caller), caller);
}
//////////////////////////工廠, Iterator類產品類
//說明,因爲Iterator包含很多種類,有LinkList中的ListItr、ArrayList中的ListItr、Vector中的ListItr(都是內部類),以後可能還需要擴展其他集合類的Iterator。
//提取出要創建的不同類型的對象的公共部分並封裝成接口。
interface Iterator<E>
{
boolean hasNext();
E next();
}
//LinkList中的ListItr、ArrayList中的ListItr、Vector中的ListItr根據自身特徵分別實現接口。
//工廠類Collection(LinkList、ArrayList、Vector)中創建產品。
Iterator<Object> it=list.iterator();
//////////////////////////抽象工廠 java.sql.Connection
//說明,抽象工廠重點在產品類的抽象和工廠類的抽象。
interface Connection{
//工廠要創建的產品組:Clob ,Blob ,NClob ,Statement(每個都是抽象的產品)
Clob createClob() throws SQLException;
Blob createBlob() throws SQLException;
NClob createNClob() throws SQLException;
Statement createStatement() throws SQLException;
......
}
//抽象產品Statement由很多產品對象的公共部分組成接口
interface Statement{
boolean execute(String sql) throws SQLException;
ResultSet getResultSet() throws SQLException;
.....
}
//具體的創建對象可以實現Statement功能形成不同的對象。
//Clob ,Blob ,NClob同是抽象產品可以具體化到很多產品
//大工廠實現Connection接口將對象組合。
/////////工廠模式可以看出抽象工廠的組內只有一種類型。
建造者模式
目標:
將一個複雜對象的構建和它的表示分離。重點在抽象出類的Build類。
why-思考:
怎麼將一個複雜的類構建尼?構建後怎麼達到分離尼?
How-思考:
類的構建主要是對類的成員變量進行重新設置,因爲每個成員變量可以取不同的值,但是最後都是需要設置的,所以對每個成員變量可以抽取出各自的的設置部分,從而將類的構建分離出。
正常示例:
//JDK中沒有找到好的示例,列舉兩種方式。
//////////////////////////////////////////////方式一
public class Test
//複雜類
{
private String part1;
private String part2;
private String part3;
......
}
//分離Build,抽象化,重點
interface Build{
public interface ICarBuilder
{
public void buildpart1();
public void buildpart2();
public void buildpart3();
Test buildTest();
}
//ConBuild實現Build接口
conBuild.buildpart1();
......
Test test=conBuild.buildTest();
}
//////////////////////////////////////////////方式二
//將Build封裝在要創建的對象內部。
Class Test{
private String part1;
private String part2;
private String part3;
......
private ClassTest(Build build){
this.part1=build.part1;
......
}
public static Class Build{
private String part1;
private String part2;
private String part3;
public Builder part1(string val){
this.part1= val;
return this;
}
public Builder part2(string val){
this.part2= val;
return this;
}
......
public Test build(){
return new Build(this);
}
}
}
//通過分離者Build來創建對象實例
Test test=new Test.Build().part1("1").part2("2").part3("3").build();
//方式二相對方式一擴展性更弱,好處是易於代碼的管理
原型模式
目標:
用原型實例大量的複製創建新的對象。重點是需要大量創建新對象。
JDK中的示例:
接口Cloneable的用法
感想
對創建型模式的感想(到模式中去)
1.明確項目中要創建的對象是否只需要一個。或者是否需要大批覆制創建。
2.要創建的對象是否很複雜,複雜體現在該對象對應的類的成員變量是否包含多個,並且成員變量多變,賦值過程分離出來是否更好。
3.要創建的對象的類型是否很多,學會抽象出共同部分,當類型多,或者多變的情況,一定首先想到要面向接口編程,抽取共同部分,然後**分角色**考慮問題是工廠者,對象產品或者建造者。
----分角色思考問題很重要,抽取共同部分也很重要!!!-------