設計模式精髓篇之創建型

說明

借鑑的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.要創建的對象的類型是否很多,學會抽象出共同部分,當類型多,或者多變的情況,一定首先想到要面向接口編程,抽取共同部分,然後**分角色**考慮問題是工廠者,對象產品或者建造者。

----分角色思考問題很重要,抽取共同部分也很重要!!!-------
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章