設(shè)計(jì)模式與架構(gòu)03 -- 原型模式,建造者模式

原型模式

  • 原型模式:用一個(gè)已經(jīng)創(chuàng)建的實(shí)例作為原型,通過(guò)復(fù)制該原型對(duì)象來(lái)創(chuàng)建一個(gè)和原型對(duì)象相同的對(duì)象鼎姊;
  • 原型模式的角色:
    • 抽象原型類:規(guī)定了具體原型對(duì)象必須實(shí)現(xiàn)的clone()方法婆赠;
    • 具體原型類:實(shí)現(xiàn)抽象原型類的clone()方法妙黍,它是可以被復(fù)制的對(duì)象做粤;
  • UML類圖如下:
image.png
  • 原型模式的克隆分為淺克隆與深克隆:
    • 淺克缕隆:創(chuàng)建一個(gè)新對(duì)象阳距,新對(duì)象的屬性與原來(lái)對(duì)象完全相同,
    • 深克乱ㄏ恰:創(chuàng)建一個(gè)新對(duì)象,屬性中引用的其他對(duì)象也會(huì)被克隆蜀撑,不再指向原有對(duì)象地址糊肤;
  • 在Java中的Object類中提供了clone()方法來(lái)實(shí)現(xiàn)克隆拗踢,Cloneable接口就是抽象原型類叉庐,而實(shí)現(xiàn)了Cloneable接口的子類就是具體原型類兴溜;
  • 代碼實(shí)現(xiàn)如下:
import androidx.annotation.NonNull;

public class Realizetype implements Cloneable{

    public Realizetype() {
        System.out.println("具體原型對(duì)象查創(chuàng)建成功");
    }

    @NonNull
    @Override
    public Realizetype clone() throws CloneNotSupportedException {
        System.out.println("具體原型對(duì)象復(fù)制成功");
        return (Realizetype) super.clone();
    }
}
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.example.sign.prototype.Realizetype;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Realizetype realizetype = new Realizetype();
        try {
            Realizetype clone = realizetype.clone();
            System.out.println("原型與克隆是否是同一個(gè)對(duì)象" + (realizetype == clone));
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
  • 案例:三好學(xué)生的獎(jiǎng)狀穿稳,同一學(xué)校三好學(xué)生的獎(jiǎng)狀除了獲獎(jiǎng)人姓名不同央拖,其他都相同柏蘑,可以使用原型模式復(fù)制多個(gè)三好學(xué)生獎(jiǎng)狀,然后再修改獎(jiǎng)狀上的名字即可觉阅,UML類圖如下:
image.png
  • 代碼實(shí)現(xiàn)如下:
import androidx.annotation.NonNull;

public class Citation implements Cloneable{
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public void show() {
        System.out.println(name + "同學(xué): 在2021年12月1日 獲取三號(hào)學(xué)生,特發(fā)此狀");
    }

    @NonNull
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.example.sign.prototype.Citation;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Citation citation = new Citation();
        try {
            Citation c1 = citation.clone();
            c1.setName("張三");
            citation.setName("李四");
            citation.show();
            c1.show();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
  • 使用場(chǎng)景:
    • 對(duì)象創(chuàng)建非常復(fù)雜震檩,可使用原型模式快捷創(chuàng)建對(duì)象沸毁;
    • 性能和安全要求比較高的;
擴(kuò)展(深克隆)
  • 將三好學(xué)生獎(jiǎng)狀類Citation的name 屬性 修改為Student 類型的屬性呀潭,代碼如下:
public class Student {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
import androidx.annotation.NonNull;

public class Citation implements Cloneable{
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public void show() {
        System.out.println(student.getName() + "同學(xué): 在2021年12月1日 獲取三號(hào)學(xué)生身害,特發(fā)此狀");
    }

    @NonNull
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.example.sign.prototype.Citation;
import com.example.sign.prototype.Student;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Citation citation = new Citation();
        Student student = new Student();
        student.setName("張三");
        citation.setStudent(student);

        try {
            Citation c1 = citation.clone();
            c1.getStudent().setName("李四");
            citation.show(); //李四
            c1.show(); //李四
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }
    }
}
  • citationc1指向同一個(gè)對(duì)象;
  • 下面通過(guò)序列化技術(shù),實(shí)現(xiàn)對(duì)象的深克隆抢埋,代碼如下:
import java.io.Serializable;

public class Student implements Serializable {

    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }
}
import androidx.annotation.NonNull;
import java.io.Serializable;

public class Citation implements Cloneable, Serializable {
    private Student student;

    public Student getStudent() {
        return student;
    }

    public void setStudent(Student student) {
        this.student = student;
    }

    public void show() {
        System.out.println(student.getName() + "同學(xué): 在2021年12月1日 獲取三號(hào)學(xué)生,特發(fā)此狀");
    }

    @NonNull
    @Override
    public Citation clone() throws CloneNotSupportedException {
        return (Citation) super.clone();
    }
}
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.example.sign.prototype.Citation;
import com.example.sign.prototype.Student;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Citation citation = new Citation();
        Student student = new Student();
        student.setName("張三");
        citation.setStudent(student);

        //創(chuàng)建輸出流
        try {
            //將對(duì)象序列化到磁盤文件
            ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("User/liyanyan/desktop/a.txt"));
            //寫對(duì)象
            oos.writeObject(citation);
            oos.close();
            ObjectInputStream ois = new ObjectInputStream(new FileInputStream("User/liyanyan/desktop/a.txt"));
            Citation citation1 = (Citation) ois.readObject();
            ois.close();
            Student student1 = citation1.getStudent();
            student1.setName("李四");
            citation.show(); //張三
            citation1.show(); //李四
        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}
  • citationcitation1指向的是兩個(gè)不同的對(duì)象戏自,其中Citation類與Student類都必須實(shí)現(xiàn)Serializable接口和二;
  • 上述的淺克隆徘铝,深克隆與iOS中淺拷貝,深拷貝的原理是相同的惯吕;

建造者模式

  • 建造者模式:將一個(gè)復(fù)雜對(duì)象的構(gòu)建與表示分離惕它,使得同樣的構(gòu)建過(guò)程可以創(chuàng)建不同的表示;
  • 實(shí)現(xiàn)了構(gòu)建與裝配的解耦废登,不同的構(gòu)建器淹魄,相同的裝配,可作出不同的對(duì)象堡距,相同的構(gòu)建器甲锡,不同的裝配順序也可作出不同的對(duì)象,也就實(shí)現(xiàn)了構(gòu)建算法與裝配算法之間的解耦羽戒,實(shí)現(xiàn)了更好的復(fù)用缤沦;
  • 建造者模式可以將部件與其組裝過(guò)程分開(kāi),一步一步創(chuàng)建一個(gè)復(fù)雜對(duì)象易稠,客戶只需要指定復(fù)雜對(duì)象的類型就可以得到該對(duì)象缸废,而無(wú)需知道其內(nèi)部的具體構(gòu)造細(xì)節(jié);
  • 建造者模式中的角色:
    • 抽象建造者類(Builder):定義了復(fù)雜對(duì)象各部件創(chuàng)建的接口驶社;
    • 具體建造者類:實(shí)現(xiàn)了Builder中的接口企量,完成部件的創(chuàng)建,在構(gòu)造完成之后亡电,返回產(chǎn)品實(shí)例届巩;
    • 產(chǎn)品類:需要的創(chuàng)建的復(fù)雜對(duì)象;
    • 指揮者類(Director):調(diào)用具體建造者來(lái)創(chuàng)建復(fù)雜對(duì)象的各個(gè)部分份乒,在指揮者類中恕汇,不涉及具體產(chǎn)品信息,只負(fù)責(zé)保證對(duì)象各部分完整創(chuàng)建或按某種順序創(chuàng)建或辖;
  • 下面以創(chuàng)建自行車為案例拇勃,來(lái)闡述建造者模式,首先產(chǎn)品類是自行車這個(gè)復(fù)雜對(duì)象孝凌,其包含車架與車座,車架有碳纖維月腋,鋁合金蟀架,車座有真皮瓣赂,橡膠,UML類圖如下所示:
image.png
  • 代碼實(shí)現(xiàn)如下:
public class Bike {
    private String frame;
    private String seat;

    public String getFrame() {
        return frame;
    }

    public void setFrame(String frame) {
        this.frame = frame;
    }

    public String getSeat() {
        return seat;
    }

    public void setSeat(String seat) {
        this.seat = seat;
    }
}
//抽象建造者
public abstract class Builder {
    protected Bike bike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();

    public abstract Bike createBike();
}
public class MobleBuilder extends Builder{
    @Override
    public void buildFrame() {
        bike.setFrame("碳纖維車架");
    }

    @Override
    public void buildSeat() {
        bike.setSeat("真皮車座");
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
public class OfoBuilder extends Builder{
    @Override
    public void buildFrame() {
        bike.setFrame("鋁合金車架");
    }

    @Override
    public void buildSeat() {
        bike.setSeat("橡膠車座");
    }

    @Override
    public Bike createBike() {
        return bike;
    }
}
//指揮者類 裝配 
public class Director {
    private Builder builder;

    public Director(Builder builder) {
        this.builder = builder;
    }

    public Bike construct() {
        builder.buildFrame();
        builder.buildSeat();
        return builder.bike;
    }
}
import androidx.appcompat.app.AppCompatActivity;
import android.os.Bundle;
import com.example.sign.build.Bike;
import com.example.sign.build.Director;
import com.example.sign.build.MobleBuilder;

public class MainActivity extends AppCompatActivity {
    @Override
    protected void onCreate(Bundle savedInstanceState) {
        super.onCreate(savedInstanceState);
        setContentView(R.layout.activity_main);

        Director director = new Director(new MobleBuilder());
        Bike bike = director.construct();
        System.out.println(bike.getFrame() + bike.getSeat());
    }
}
  • 上述案例是Builder模式的常規(guī)用法片拍,指揮者Director在建造者模式中具有很重要的作用煌集,它用于指導(dǎo)具體構(gòu)建者如何構(gòu)建產(chǎn)品,控制先后次序捌省,并向調(diào)用者返回完整的產(chǎn)品類苫纤,可以考慮將指揮者Director與抽象建造者類Builder進(jìn)行合并,代碼如下:
//抽象建造者
public abstract class Builder {
    protected Bike bike = new Bike();

    public abstract void buildFrame();
    public abstract void buildSeat();

    public abstract Bike createBike();
    
    public Bike construct() {
        this.buildFrame();
        this.buildSeat();
        return this.createBike();
    }
}
  • 這樣設(shè)計(jì)簡(jiǎn)化了系統(tǒng)結(jié)構(gòu)纲缓,但加重了抽象建造者Builder的職責(zé)卷拘,若指揮者Director類邏輯過(guò)于復(fù)雜,建議還是將兩者分開(kāi)祝高;
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末栗弟,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子工闺,更是在濱河造成了極大的恐慌乍赫,老刑警劉巖,帶你破解...
    沈念sama閱讀 206,968評(píng)論 6 482
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件陆蟆,死亡現(xiàn)場(chǎng)離奇詭異雷厂,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī)叠殷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,601評(píng)論 2 382
  • 文/潘曉璐 我一進(jìn)店門改鲫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人溪猿,你說(shuō)我怎么就攤上這事钩杰。” “怎么了诊县?”我有些...
    開(kāi)封第一講書人閱讀 153,220評(píng)論 0 344
  • 文/不壞的土叔 我叫張陵讲弄,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我依痊,道長(zhǎng)避除,這世上最難降的妖魔是什么? 我笑而不...
    開(kāi)封第一講書人閱讀 55,416評(píng)論 1 279
  • 正文 為了忘掉前任胸嘁,我火速辦了婚禮瓶摆,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘性宏。我一直安慰自己群井,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 64,425評(píng)論 5 374
  • 文/花漫 我一把揭開(kāi)白布毫胜。 她就那樣靜靜地躺著书斜,像睡著了一般诬辈。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上荐吉,一...
    開(kāi)封第一講書人閱讀 49,144評(píng)論 1 285
  • 那天焙糟,我揣著相機(jī)與錄音,去河邊找鬼样屠。 笑死穿撮,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的痪欲。 我是一名探鬼主播悦穿,決...
    沈念sama閱讀 38,432評(píng)論 3 401
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼勤揩!你這毒婦竟也來(lái)了咧党?” 一聲冷哼從身側(cè)響起,我...
    開(kāi)封第一講書人閱讀 37,088評(píng)論 0 261
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤陨亡,失蹤者是張志新(化名)和其女友劉穎傍衡,沒(méi)想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體负蠕,經(jīng)...
    沈念sama閱讀 43,586評(píng)論 1 300
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡蛙埂,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,028評(píng)論 2 325
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了遮糖。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片绣的。...
    茶點(diǎn)故事閱讀 38,137評(píng)論 1 334
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖欲账,靈堂內(nèi)的尸體忽然破棺而出屡江,到底是詐尸還是另有隱情,我是刑警寧澤赛不,帶...
    沈念sama閱讀 33,783評(píng)論 4 324
  • 正文 年R本政府宣布惩嘉,位于F島的核電站,受9級(jí)特大地震影響踢故,放射性物質(zhì)發(fā)生泄漏文黎。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 39,343評(píng)論 3 307
  • 文/蒙蒙 一殿较、第九天 我趴在偏房一處隱蔽的房頂上張望耸峭。 院中可真熱鬧,春花似錦淋纲、人聲如沸劳闹。這莊子的主人今日做“春日...
    開(kāi)封第一講書人閱讀 30,333評(píng)論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)本涕。三九已至儡首,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間偏友,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書人閱讀 31,559評(píng)論 1 262
  • 我被黑心中介騙來(lái)泰國(guó)打工对供, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留位他,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 45,595評(píng)論 2 355
  • 正文 我出身青樓产场,卻偏偏與公主長(zhǎng)得像鹅髓,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子京景,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 42,901評(píng)論 2 345

推薦閱讀更多精彩內(nèi)容