android 設(shè)計(jì)模式總結(jié)之23種設(shè)計(jì)模式

一猪叙、什么是設(shè)計(jì)模式

  • 設(shè)計(jì)模式(Design pattern)是一套被反復(fù)使用赘风、多數(shù)人知曉的夹囚、經(jīng)過分類編目的、代碼設(shè)計(jì)經(jīng)驗(yàn)的總結(jié)邀窃。使用設(shè)計(jì)模式是為了可重用代碼荸哟、讓代碼更容易被他人理解、保證代碼可靠性瞬捕。 毫無疑問鞍历,設(shè)計(jì)模式于己于他人于系統(tǒng)都是多贏的,設(shè)計(jì)模式使代碼編制真正工程化肪虎,設(shè)計(jì)模式是軟件工程的基石劣砍,如同大廈的一塊塊磚石一樣。項(xiàng)目中合理的運(yùn)用設(shè)計(jì)模式可以完美的解決很多問題扇救,每種模式在現(xiàn)在中都有相應(yīng)的原理來與之對(duì)應(yīng)刑枝,每一個(gè)模式描述了一個(gè)在我們周圍不斷重復(fù)發(fā)生的問題,以及該問題的核心解決方案爵政,這也是它能被廣泛應(yīng)用的原因

二仅讽、為什么學(xué)習(xí)設(shè)計(jì)模式

  • 它是很多人很多年以來的經(jīng)驗(yàn)智慧的總結(jié),教你怎樣更高效的來玩耍代碼钾挟,使原來單一的代碼模式變得有趣洁灵,漂亮。他是使編程藝術(shù)化的入門掺出。

三徽千、常見的面向?qū)ο笤O(shè)計(jì)原則

1、迪米特法則汤锨,又稱最少知道原則(Demeter Principle)

  • 最少知道原則是指:一個(gè)實(shí)體應(yīng)當(dāng)盡量少地與其他實(shí)體之間發(fā)生相互作用双抽,使得系統(tǒng)功能模塊相對(duì)獨(dú)立。

從依賴者的角度來說闲礼,只依賴應(yīng)該依賴的對(duì)象牍汹。
從被依賴者的角度說铐维,只暴露應(yīng)該暴露的方法。降低耦合

假設(shè)類A實(shí)現(xiàn)了某個(gè)功能慎菲,類B需要調(diào)用類A的去執(zhí)行這個(gè)功能嫁蛇,那么類A應(yīng)該只暴露一個(gè)函數(shù)給類B,這個(gè)函數(shù)表示是實(shí)現(xiàn)這個(gè)功能的函數(shù)露该,而不是讓類A把實(shí)現(xiàn)這個(gè)功能的所有細(xì)分的函數(shù)暴露給B睬棚。

2、里氏代換原則

  • 基類和子類之間的關(guān)系解幼。子類可以擴(kuò)展父類的功能抑党,但不能改變父類原有的功能。也就是說:子類繼承父類時(shí)撵摆,除添加新的方法完成新增功能外底靠,盡量不要重寫父類的方法。

關(guān)于里氏替換原則的例子特铝,最有名的是“正方形不是長方形”苛骨。當(dāng)然,生活中也有很多類似的例子苟呐,例如,企鵝俐筋、鴕鳥和幾維鳥從生物學(xué)的角度來劃分牵素,它們屬于鳥類;但從類的繼承關(guān)系來看澄者,由于它們不能繼承“鳥”會(huì)飛的功能笆呆,所以它們不能定義成“鳥”的子類。同樣粱挡,由于“氣球魚”不會(huì)游泳赠幕,所以不能定義成“魚”的子類;“玩具炮”炸不了敵人询筏,所以不能定義成“炮”的子類等榕堰。

3、依賴倒轉(zhuǎn)原則(Dependence Inversion Principle)

它降低了客戶與實(shí)現(xiàn)模塊之間的耦合嫌套。

由于在軟件設(shè)計(jì)中逆屡,細(xì)節(jié)具有多變性,而抽象層則相對(duì)穩(wěn)定踱讨,因此以抽象為基礎(chǔ)搭建起來的架構(gòu)要比以細(xì)節(jié)為基礎(chǔ)搭建起來的架構(gòu)要穩(wěn)定得多魏蔗。這里的抽象指的是接口或者抽象類,而細(xì)節(jié)是指具體的實(shí)現(xiàn)類痹筛。
使用接口或者抽象類的目的是制定好規(guī)范和契約莺治,而不去涉及任何具體的操作廓鞠,把展現(xiàn)細(xì)節(jié)的任務(wù)交給它們的實(shí)現(xiàn)類去完成。

比如常見的參數(shù)里傳的是父類谣旁,而不是具體類床佳,比如一個(gè)售賣功能里面的參數(shù)是商店,商店有可能是北京商店蔓挖,也可能是上海商店夕土,所以這個(gè)號(hào)參數(shù)要使用商店這個(gè)類而不是具體的某個(gè)商店

4、接口隔離原則(Interface Segregation Principle)

  • 這個(gè)原則的意思是:使用多個(gè)隔離的接口瘟判,比使用單個(gè)接口要好怨绣。它還有另外一個(gè)意思是:降低類之間的耦合度。由此可見拷获,其實(shí)設(shè)計(jì)模式就是從大型軟件架構(gòu)出發(fā)篮撑、便于升級(jí)和維護(hù)的軟件設(shè)計(jì)思想,它強(qiáng)調(diào)降低依賴匆瓜,降低耦合赢笨。以下這里例子一眼就能對(duì)比出接口隔離的好處了
public interface UserService {
    
    public void login(String username, String password);
    public void register(String email, String username, String password);
    public void logError(String msg);
    public void sendEmail(String email);
    
} 

5、開閉原則(Open Close Principle)

  • 開閉原則的意思是:對(duì)擴(kuò)展開放驮吱,對(duì)修改關(guān)閉茧妒。
    在程序需要進(jìn)行拓展的時(shí)候,不能去修改原有的代碼左冬,實(shí)現(xiàn)一個(gè)熱插拔的效果桐筏。簡言之,是為了使程序的擴(kuò)展性好拇砰,易于維護(hù)和升級(jí)梅忌。想要達(dá)到這樣的效果,我們需要使用接口和抽象類除破,后面的具體設(shè)計(jì)中我們會(huì)提到這點(diǎn)牧氮。

6、單一原則(Composite Reuse Principle)

  • 一個(gè)類單一職責(zé)瑰枫,防止耦合

四踱葛、設(shè)計(jì)模式分類

如下圖所示:

401339-20170928225241215-295252070.png

創(chuàng)建型模式

這些設(shè)計(jì)模式提供了一種在創(chuàng)建對(duì)象的同時(shí)隱藏創(chuàng)建邏輯的方式,而不是使用新的運(yùn)算符直接實(shí)例化對(duì)象光坝。這使得程序在判斷針對(duì)某個(gè)給定實(shí)例需要?jiǎng)?chuàng)建哪些對(duì)象時(shí)更加靈活剖毯。

public class ShapeFactory {
    
  //普通工廠模式教馆,不符合開閉原則
   public Shape getShape(String shapeType){
       
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}

抽象工廠更符合開-閉原則逊谋,降低耦合,但抽象工廠模式很難支持新種類產(chǎn)品的變化土铺。類復(fù)雜胶滋。實(shí)際應(yīng)用中使用簡單工廠多點(diǎn)

public class Singleton {  
//餓漢模式板鬓,簡單,線程安全究恤,效率高俭令,但一開始就加載了,容易產(chǎn)生垃圾
    private static Singleton instance = new Singleton();  
    private Singleton (){}  
    public static Singleton getInstance() {  
    return instance;  
    }  
}
public class User {
    private final String firstName;     // 必傳參數(shù)
    private final String lastName;      // 必傳參數(shù)
    private final int age;              // 可選參數(shù)
    private final String phone;         // 可選參數(shù)
    private final String address;       // 可選參數(shù)

    private User(UserBuilder builder) {
        this.firstName = builder.firstName;
        this.lastName = builder.lastName;
        this.age = builder.age;
        this.phone = builder.phone;
        this.address = builder.address;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public int getAge() {
        return age;
    }

    public String getPhone() {
        return phone;
    }

    public String getAddress() {
        return address;
    }

    public static class UserBuilder {
        private final String firstName;
        private final String lastName;
        private int age;
        private String phone;
        private String address;

        public UserBuilder(String firstName, String lastName) {
            this.firstName = firstName;
            this.lastName = lastName;
        }

        public UserBuilder age(int age) {
            this.age = age;
            return this;
        }

        public UserBuilder phone(String phone) {
            this.phone = phone;
            return this;
        }

        public UserBuilder address(String address) {
            this.address = address;
            return this;
        }

        public User build() {
            return new User(this);
        }
    }
}


調(diào)用
new User.UserBuilder("王", "小二")
                .age(20)
                .phone("123456789")
                .address("亞特蘭蒂斯大陸")
                .build();
  • 原型模式 (Prototype Pattern):通過拷貝原型創(chuàng)建新的對(duì)象抄腔,當(dāng)我們的類初始化需要消耗很多的資源時(shí),就可以使用原型模式理张,因?yàn)槲覀兊目寺〔粫?huì)執(zhí)行構(gòu)造方法赫蛇,避免了初始化占有的時(shí)間和空間。

1雾叭、淺克隆:
對(duì)于數(shù)據(jù)類型是基本數(shù)據(jù)類型的成員變量悟耘,淺拷貝會(huì)直接進(jìn)行值傳遞,也就是將該屬性值復(fù)制一份給新的對(duì)象织狐。

對(duì)于數(shù)據(jù)類型是引用數(shù)據(jù)類型的成員變量暂幼,比如說成員變量是某個(gè)數(shù)組,某個(gè)類型的對(duì)象等移迫,那么淺拷貝會(huì)進(jìn)行引用傳遞旺嬉,也就是只是該成員變量的引用值(內(nèi)存地址)復(fù)制一份給新的對(duì)象,因?yàn)閷?shí)際上兩個(gè)對(duì)象的該成員變量都指向同一個(gè)實(shí)例厨埋,在這種情況下鹰服,在一個(gè)對(duì)象中修改該成員變量會(huì)影響到另一個(gè)對(duì)象的該成員變量值。

//這里不實(shí)現(xiàn)Serializable接口也可以實(shí)現(xiàn)淺克隆
public class User implements Cloneable,Serializable{
    
    private String name;
    
    private Date birth;
    
    private int age;

    public String getName() {
        return name;
    }

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

    public Date getBirth() {
        return birth;
    }

    public void setBirth(Date birth) {
        this.birth = birth;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
    
    /**
     * 實(shí)現(xiàn)克隆的方法
     */
    public Object clone() throws CloneNotSupportedException{
        return super.clone();
    }
}
    //使用
    Date date =  new Date(1231231231231l);
    User user = new User();
    user.setName("波波烤鴨");
    user.setAge(18);
    user.setBirth(date);
    System.out.println("----輸出原型對(duì)象的屬性------");
    System.out.println(user);
    System.out.println(user.getName());
    System.out.println(user.getBirth());
    // 克隆對(duì)象
    User user1 =(User) user.clone();
    // 修改原型對(duì)象中的屬性
    date.setTime(123231231231l);
    System.out.println(user.getBirth());
    
    // 修改參數(shù)
    user1.setName("dpb");
    System.out.println("-------克隆對(duì)象的屬性-----");
    System.out.println(user1);
    System.out.println(user1.getName());
    System.out.println(user1.getBirth());

//打印如下
----輸出原型對(duì)象的屬性-----
com.dpb.prototype.User@15db9742
波波烤鴨
Tue Jan 06 16:40:31 CST 2009 # 1
Tue Nov 27 14:53:51 CST 1973 # 2

-------克隆對(duì)象的屬性-----
com.dpb.prototype.User@5c647e05
dpb
Tue Nov 27 14:53:51 CST 1973 # 和2的結(jié)果一樣 說明兩個(gè)對(duì)象的Date的引用是同一個(gè)

//雖然產(chǎn)生了兩個(gè)完全不同的對(duì)象揽咕,但是被復(fù)制的對(duì)象的所有變量都含有與原來的對(duì)象相同的值,而所有的對(duì)其他對(duì)象(比如Date)的引用都仍然指向原來的對(duì)象

深拷貝代碼實(shí)例:
方式一:重寫clone方法

public class DeepCloneableTarget implements Serializable, Cloneable {

    private static final long serialVersionUID = 1L;

    private String cloneName;

    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    //因?yàn)樵擃惖膶傩蕴撞耍际荢tring亲善,因此我們這里使用默認(rèn)的clone完成即可.
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}



public class DeepProtoType implements Serializable, Cloneable {

    public String name;
    public DeepCloneableTarget deepCloneableTarget;

    public DeepProtoType() {
        super();
    }

    //深拷貝 - 方式1 使用clone 方法

    @Override
    protected Object clone() throws CloneNotSupportedException {
        Object deep = null;
        //完成對(duì)基本數(shù)據(jù)類型(屬性)和String的克隆
        deep = super.clone();
        //對(duì)引用類型的屬性,進(jìn)行單獨(dú)的處理逗柴。
        DeepProtoType deepProtoType = (DeepProtoType) deep;
        deepProtoType.deepCloneableTarget = (DeepCloneableTarget) deepCloneableTarget.clone();

        return deep;
    }
}

public class Client {
    public static void main(String[] args) throws  Exception{
        DeepProtoType p = new DeepProtoType();
        p.name="宋江";
        p.deepCloneableTarget=new DeepCloneableTarget("大牛","小牛的");

        //方式1 完成深拷貝

        DeepProtoType p2=(DeepProtoType)p.clone();
        System.out.println("p.name="+p.name+"p.deepCloneableTarget="+p.deepCloneableTarget.hashCode());
        System.out.println("p2.name="+p2.name+"p.deepCloneableTarget="+p2.deepCloneableTarget.hashCode());

    }
}

方式二:通過對(duì)象序列化來實(shí)現(xiàn)深拷貝(推薦使用)
DeepCloneableTarget類

public class DeepCloneableTarget implements Serializable, Cloneable {

    private static final long serialVersionUID = 1L;

    private String cloneName;

    private String cloneClass;

    public DeepCloneableTarget(String cloneName, String cloneClass) {
        this.cloneName = cloneName;
        this.cloneClass = cloneClass;
    }

    //因?yàn)樵擃惖膶傩杂纪罚际荢tring,因此我們這里使用默認(rèn)的clone完成即可.
    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }
}
DeepProtoType 類

public class DeepProtoType implements Serializable, Cloneable {

    public String name;
    public DeepCloneableTarget deepCloneableTarget;

    public DeepProtoType() {
        super();
    }

    //深拷貝 -  方式2 通過對(duì)象序列化實(shí)現(xiàn)(推薦使用)

    public Object deepClone() {
        //創(chuàng)建流對(duì)象
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;

        try {

            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(this);//當(dāng)前這個(gè)對(duì)象以對(duì)象流的方式輸出

            //反序列化
            bis = new ByteArrayInputStream(bos.toByteArray());
            ois = new ObjectInputStream(bis);

            DeepProtoType copyObj = (DeepProtoType) ois.readObject();

            return copyObj;
        } catch (Exception e) {
            e.printStackTrace();
            return null;
        } finally {
            try {
                bos.close();
                oos.close();
                bis.close();
                ois.close();
            } catch (Exception e2) {
                e2.printStackTrace();
            }
        }
    }
}
Client 測試用例

public class Client {
    public static void main(String[] args) throws Exception {
        DeepProtoType p = new DeepProtoType();
        p.name = "宋江";
        p.deepCloneableTarget = new DeepCloneableTarget("大牛", "小牛的");

        //方式2 完成深拷貝
        DeepProtoType p3=(DeepProtoType) p.deepClone();

        System.out.println("p.name=" + p.name + "p.deepCloneableTarget=" + p.deepCloneableTarget.hashCode());
        System.out.println("p3.name=" + p3.name + "p.deepCloneableTarget=" + p3.deepCloneableTarget.hashCode());

    }
}

public class Computer {
    //我們的電腦需要連接1:轉(zhuǎn)按器才可以1:網(wǎng)
    public void net(NetToUsb adapter) {
        //.上網(wǎng)的具體實(shí)現(xiàn)戏溺, 找“個(gè)轉(zhuǎn)接義
        adapter.handleRequest();
    }

    public static void main(String[] args) {
        Computer computer = new Computer(); //電腦
        Adaptee adaptee = new Adaptee(); //網(wǎng)線
        Adapter adapter = new Adapter(); //轉(zhuǎn)按器
        computer.net(adapter);*/
}

結(jié)構(gòu)型模式

這些設(shè)計(jì)模式關(guān)注類和對(duì)象的組合渣蜗。

//要被適配的類:網(wǎng)線
public class Adaptee {
    public void request() {
        System.out.println("連接網(wǎng)線上網(wǎng)");
    }
}

//真正的適配器,需 要連接USB,連接網(wǎng)線~
public class Adapter extends Adaptee implements NetToUsb {
    @Override
    public void handleRequest() {
        //上網(wǎng)的具體實(shí)現(xiàn)旷祸,找一個(gè)轉(zhuǎn)接頭
        super.request();
    }
}

//按1口轉(zhuǎn)換器的抽象實(shí)現(xiàn)~
public interface NetToUsb {
//作1川:處理請(qǐng)求耕拷,網(wǎng)線=>usb
public void handleRequest();
}


public class Computer {
    //我們的電腦需要連接1:轉(zhuǎn)按器才可以1:網(wǎng)
    public void net(NetToUsb adapter) {
        //.上網(wǎng)的具體實(shí)現(xiàn), 找“個(gè)轉(zhuǎn)接義
        adapter.handleRequest();
    }

    public static void main(String[] args) {
/*        //電腦托享,適配器骚烧,網(wǎng)線~   使用繼承的方式
        Computer computer = new Computer(); //電腦
        Adaptee adaptee = new Adaptee(); //網(wǎng)線
        Adapter adapter = new Adapter(); //轉(zhuǎn)按器
        computer.net(adapter);*/

        System.out.println("++++++++++++++++++++++++++++++");

        //電腦浸赫,適配器,網(wǎng)線~   使用組合的方式
        Computer computer = new Computer(); //電腦
        Adaptee adaptee = new Adaptee(); //網(wǎng)線
        Adapter2 adapter = new Adapter2(adaptee); //轉(zhuǎn)按器

        computer.net(adapter);
    }
}

  • [裝飾器模式 (Decorator Pattern):允許向一個(gè)現(xiàn)有的對(duì)象添加新的功能赃绊,同時(shí)又不改變其結(jié)構(gòu)既峡。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它是作為現(xiàn)有的類的一個(gè)包裝碧查。何時(shí)使用:在不想增加很多子類的情況下擴(kuò)展類
第一代機(jī)器人只會(huì)跳舞运敢,第二代機(jī)器人通過傳入第一代機(jī)器人擁有了跳舞功能,然后增加唱歌功能呢忠售。
public interface Robot {
   void dance();
}
public class  firstRobot implements Robot {
 
   @Override
   public void dance() {
      System.out.println("dance: dance");
   }
}
public class twoRobot implements Robot {
   protected Robot rebot;
 
   public ShapeDecorator(Robot rebot){
      this.rebot = rebot;
   }
 
   public void dance(){
      rebot.dance();
   }  
  public void singing(){

  }
}
  • 橋接模式 (Bridge Pattern):兩個(gè)維度獨(dú)立變化传惠,依賴方式實(shí)現(xiàn)抽象與實(shí)現(xiàn)分離:需要一個(gè)作為橋接的接口/抽象類,多個(gè)角度的實(shí)現(xiàn)類依賴注入到抽象類档痪,使它們?cè)诔橄髮咏⒁粋€(gè)關(guān)聯(lián)關(guān)系


    image.png
//品牌
public interface Brand {
    void info();
}

public class Lenovo implements Brand {
    @Override
    public void info() {
        System.out.print("聯(lián)想");
    }
}

public class Apple implements Brand {
    @Override
    public void info() {
        System.out.print("蘋果");
    }
}
//抽象的電腦類型類
public abstract class Computer {
    //組合涉枫,品牌~
    protected Brand brand;

    public Computer(Brand brand) {
        this.brand = brand;
    }

    public void info() {
        brand.info();//自帶品牌
    }
}
class Laptop extends Computer {
    public Laptop(Brand brand) {
        super(brand);
    }

    @Override
    public void info() {
        super.info();
        System.out.print("筆記本");
    }
}
  • 外觀模式 (Facade Pattern):在客戶端和復(fù)雜系統(tǒng)之間再加一層,這一次將調(diào)用順序腐螟、依賴關(guān)系等處理好愿汰。即封裝底層實(shí)現(xiàn),隱藏系統(tǒng)的復(fù)雜性乐纸,并向客戶端提供了一個(gè)客戶端可以訪問系統(tǒng)的高層接口
public class CPU {   
    public void startup(){  
        System.out.println("cpu startup!");  
    }  
    public void shutdown(){  
        System.out.println("cpu shutdown!");  
    }  
}
 
public class Memory {    
    public void startup(){  
        System.out.println("memory startup!");  
    }  
    public void shutdown(){  
        System.out.println("memory shutdown!");  
    }  
} 
 
public class Disk {  
    public void startup(){  
        System.out.println("disk startup!");  
    }  
    public void shutdown(){  
        System.out.println("disk shutdown!");  
    }  
}
public class Computer {  
    private CPU cpu;  
    private Memory memory;  
    private Disk disk;  
 
    public Computer(){  
        cpu = new CPU();  
        memory = new Memory();  
        disk = new Disk();  
    }  
 
    public void startup(){  
        System.out.println("start the computer!");  
        cpu.startup();  
        memory.startup();  
        disk.startup();  
        System.out.println("start computer finished!");  
    }  
 
    public void shutdown(){  
        System.out.println("begin to close the computer!");  
        cpu.shutdown();  
        memory.shutdown();  
        disk.shutdown();  
        System.out.println("computer closed!");  
    }  
}
Computer computer = new Computer();  
computer.startup();  
computer.shutdown();
  • 代理模式 (Proxy Pattern):為其他對(duì)象提供一種代理以控制對(duì)這個(gè)對(duì)象的訪問:增加中間層(代理層)衬廷,代理類與底層實(shí)現(xiàn)類實(shí)現(xiàn)共同接口,并創(chuàng)建底層實(shí)現(xiàn)類對(duì)象(底層實(shí)現(xiàn)類對(duì)象依賴注入代理類)汽绢,以便向外界提供功能接口
public interface Image {
   void display();
}
public class RealImage implements Image {
 
   private String fileName;
 
   public RealImage(String fileName){
      this.fileName = fileName;
      loadFromDisk(fileName);
   }
 
   @Override
   public void display() {
      System.out.println("Displaying " + fileName);
   }
 
   private void loadFromDisk(String fileName){
      System.out.println("Loading " + fileName);
   }
}
public class ProxyImage implements Image{
 
   private RealImage realImage;
   private String fileName;
 
   public ProxyImage(String fileName){
      this.fileName = fileName;
   }
 
   @Override
   public void display() {
      if(realImage == null){
         realImage = new RealImage(fileName);
      }
      realImage.display();
   }
}
public class ProxyPatternDemo {
   public static void main(String[] args) {
      Image image = new ProxyImage("test_10mb.jpg");
      // 圖像將從磁盤加載
      image.display(); 
      System.out.println("");
      // 圖像不需要從磁盤加載
      image.display();  
   }
}
  • 過濾器模式 (Filter吗跋、Criteria Pattern):使用不同的標(biāo)準(zhǔn)來過濾一組對(duì)象,通過邏輯運(yùn)算以解耦的方式把它們連接起來
    https://www.runoob.com/design-pattern/filter-pattern.html

  • 組合模式 (Composite Pattern):用戶對(duì)單個(gè)對(duì)象和組合對(duì)象的使用具有一致性的統(tǒng)一接口宁昭,何時(shí)使用: 1跌宛、您想表示對(duì)象的部分-整體層次結(jié)構(gòu)(樹形結(jié)構(gòu))。2积仗、您希望用戶忽略組合對(duì)象與單個(gè)對(duì)象的不同疆拘,用戶將統(tǒng)一地使用組合結(jié)構(gòu)中的所有對(duì)象。

public class Employee {
   private String name;
   private String dept;
   private int salary;
   private List<Employee> subordinates;
 
   //構(gòu)造函數(shù)
   public Employee(String name,String dept, int sal) {
      this.name = name;
      this.dept = dept;
      this.salary = sal;
      subordinates = new ArrayList<Employee>();
   }
 
   public void add(Employee e) {
      subordinates.add(e);
   }
 
   public void remove(Employee e) {
      subordinates.remove(e);
   }
 
   public List<Employee> getSubordinates(){
     return subordinates;
   }
 
   public String toString(){
      return ("Employee :[ Name : "+ name 
      +", dept : "+ dept + ", salary :"
      + salary+" ]");
   }   
}
public class CompositePatternDemo {
   public static void main(String[] args) {
      Employee CEO = new Employee("John","CEO", 30000);
 
      Employee headSales = new Employee("Robert","Head Sales", 20000);
 
      Employee headMarketing = new Employee("Michel","Head Marketing", 20000);
 
      Employee clerk1 = new Employee("Laura","Marketing", 10000);
      Employee clerk2 = new Employee("Bob","Marketing", 10000);
 
      Employee salesExecutive1 = new Employee("Richard","Sales", 10000);
      Employee salesExecutive2 = new Employee("Rob","Sales", 10000);
 
      CEO.add(headSales);
      CEO.add(headMarketing);
 
      headSales.add(salesExecutive1);
      headSales.add(salesExecutive2);
 
      headMarketing.add(clerk1);
      headMarketing.add(clerk2);
 
      //打印該組織的所有員工
      System.out.println(CEO); 
      for (Employee headEmployee : CEO.getSubordinates()) {
         System.out.println(headEmployee);
         for (Employee employee : headEmployee.getSubordinates()) {
            System.out.println(employee);
         }
      }        
   }
}
  • 享元模式 (Flyweight Pattern):主要用于減少創(chuàng)建對(duì)象的數(shù)量寂曹,以減少內(nèi)存占用和提高性能哎迄。這種類型的設(shè)計(jì)模式屬于結(jié)構(gòu)型模式,它提供了減少對(duì)象數(shù)量從而改善應(yīng)用所需的對(duì)象結(jié)構(gòu)的方式隆圆。主要解決:在有大量對(duì)象時(shí)漱挚,有可能會(huì)造成內(nèi)存溢出,我們把其中共同的部分抽象出來渺氧,如果有相同的業(yè)務(wù)請(qǐng)求旨涝,直接返回在內(nèi)存中已有的對(duì)象,避免重新創(chuàng)建侣背。
public class Circle implements Shape {
   private String color;
   private int x;
   private int y;
   private int radius;
 
   public Circle(String color){
      this.color = color;     
   }
 
   public void setX(int x) {
      this.x = x;
   }
 
   public void setY(int y) {
      this.y = y;
   }
 
   public void setRadius(int radius) {
      this.radius = radius;
   }
 
   @Override
   public void draw() {
      System.out.println("Circle: Draw() [Color : " + color 
         +", x : " + x +", y :" + y +", radius :" + radius);
   }
}

public class ShapeFactory {
   private static final HashMap<String, Shape> circleMap = new HashMap<>();
 
   public static Shape getCircle(String color) {
      Circle circle = (Circle)circleMap.get(color);
 
      if(circle == null) {
         circle = new Circle(color);
         circleMap.put(color, circle);
         System.out.println("Creating circle of color : " + color);
      }
      return circle;
   }
}
//隨機(jī)調(diào)用颊糜,有用過的會(huì)從hashmap中取出
public class FlyweightPatternDemo {
   private static final String colors[] = 
      { "Red", "Green", "Blue", "White", "Black" };
   public static void main(String[] args) {
 
      for(int i=0; i < 20; ++i) {
         Circle circle = 
            (Circle)ShapeFactory.getCircle(getRandomColor());
         circle.setX(getRandomX());
         circle.setY(getRandomY());
         circle.setRadius(100);
         circle.draw();
      }
   }
   private static String getRandomColor() {
      return colors[(int)(Math.random()*colors.length)];
   }
   private static int getRandomX() {
      return (int)(Math.random()*100 );
   }
   private static int getRandomY() {
      return (int)(Math.random()*100);
   }
}

行為型模式

這些設(shè)計(jì)模式特別關(guān)注對(duì)象之間的通信哩治。

  • 責(zé)任鏈模式(Chain of Responsibility Pattern):攔截的類都實(shí)現(xiàn)統(tǒng)一接口,每個(gè)接收者都包含對(duì)下一個(gè)接收者的引用衬鱼。將這些對(duì)象連接成一條鏈业筏,并且沿著這條鏈傳遞請(qǐng)求,直到有對(duì)象處理它為止鸟赫。
    //抽象處理者角色
abstract class Handler {
    private Handler next;
    public void setNext(Handler next) {
        this.next = next;
    }
    public Handler getNext() {
        return next;
    }
    //處理請(qǐng)求的方法
    public abstract void handleRequest(String request);
}
//具體處理者角色1
class ConcreteHandler1 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("one")) {
            System.out.println("具體處理者1負(fù)責(zé)處理該請(qǐng)求蒜胖!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("沒有人處理該請(qǐng)求!");
            }
        }
    }
}
//具體處理者角色2
class ConcreteHandler2 extends Handler {
    public void handleRequest(String request) {
        if (request.equals("two")) {
            System.out.println("具體處理者2負(fù)責(zé)處理該請(qǐng)求抛蚤!");
        } else {
            if (getNext() != null) {
                getNext().handleRequest(request);
            } else {
                System.out.println("沒有人處理該請(qǐng)求台谢!");
            }
        }
    }
}
public class ChainOfResponsibilityPattern {
    public static void main(String[] args) {
        //組裝責(zé)任鏈
        Handler handler1 = new ConcreteHandler1();
        Handler handler2 = new ConcreteHandler2();
        handler1.setNext(handler2);
        //提交請(qǐng)求
        handler1.handleRequest("two");
    }
}
/抽象目標(biāo)
abstract class Subject {
    protected List<Observer> observers = new ArrayList<Observer>();
    //增加觀察者方法
    public void add(Observer observer) {
        observers.add(observer);
    }
    //刪除觀察者方法
    public void remove(Observer observer) {
        observers.remove(observer);
    }
    public abstract void notifyObserver(); //通知觀察者方法
}
//具體目標(biāo)
class ConcreteSubject extends Subject {
    public void notifyObserver() {
        System.out.println("具體目標(biāo)發(fā)生改變...");
        System.out.println("--------------");
        for (Object obs : observers) {
            ((Observer) obs).response();
        }
    }
}
//抽象觀察者
interface Observer {
    void response(); //反應(yīng)
}
//具體觀察者1
class ConcreteObserver1 implements Observer {
    public void response() {
        System.out.println("具體觀察者1作出反應(yīng)集晚!");
    }
}
//具體觀察者1
class ConcreteObserver2 implements Observer {
    public void response() {
        System.out.println("具體觀察者2作出反應(yīng)撒遣!");
    }
}

public class ObserverPattern {
    public static void main(String[] args) {
        Subject subject = new ConcreteSubject();
        Observer obs1 = new ConcreteObserver1();
        Observer obs2 = new ConcreteObserver2();
        subject.add(obs1);
        subject.add(obs2);
        subject.notifyObserver();
    }
}
  • 模板模式(Template Pattern):將這些通用算法抽象出來绰精,在一個(gè)抽象類中公開定義了執(zhí)行它的方法的方式/模板。主要解決:一些方法通用叮趴,卻在每一個(gè)子類都重新寫了這一方法扑眉。
public abstract class Game {
   abstract void initialize();
   abstract void startPlay();
   abstract void endPlay();
 
   //模板
   public final void play(){
 
      //初始化游戲
      initialize();
 
      //開始游戲
      startPlay();
 
      //結(jié)束游戲
      endPlay();
   }
}

public class Cricket extends Game {
 
   @Override
   void endPlay() {
      System.out.println("Cricket Game Finished!");
   }
 
   @Override
   void initialize() {
      System.out.println("Cricket Game Initialized! Start playing.");
   }
 
   @Override
   void startPlay() {
      System.out.println("Cricket Game Started. Enjoy the game!");
   }
}
public class Football extends Game {
 
   @Override
   void endPlay() {
      System.out.println("Football Game Finished!");
   }
 
   @Override
   void initialize() {
      System.out.println("Football Game Initialized! Start playing.");
   }
 
   @Override
   void startPlay() {
      System.out.println("Football Game Started. Enjoy the game!");
   }
}
public class TemplatePatternDemo {
   public static void main(String[] args) {
 
      Game game = new Cricket();
      game.play();
      System.out.println();
      game = new Football();
      game.play();      
   }
}
//不用命令模式条篷,添加一個(gè)界面就要修改電視類和觀看類
//電視機(jī)對(duì)象:提供了播放不同頻道的方法
public class Television {
    
    public void playCctv1() {
        System.out.println("--CCTV1--");
    }

    public void playCctv2() {
        System.out.println("--CCTV2--");
    }
}
public class Watcher {
    //持有一個(gè)
    public Television tv;

    public Watcher(Television tv) {
        this.tv = tv;
    }

    public void playCctv1() {
        tv.playCctv1();
    }

    public void playCctv2() {
        tv.playCctv2();
    }
}
 Watcher watcher = new Watcher(new Television());
        watcher.playCctv1();
        watcher.playCctv2();

//使用命令模式
public abstract class Command {
    //命令接收者:電視機(jī)
    protected Television television;

    public Command(Television television) {
        this.television = television;
    }

    //命令執(zhí)行
    abstract void execute();
}
//播放cctv1的命令
public class CCTV1Command extends Command {
    @Override
    void execute() {
        television.playCctv1();
    }
}

//播放cctv2的命令
public class CCTV6Command extends Command {
    @Override
    void execute() {
        television.playCctv2();
    }
}
————————————————
        historyCommand.add(command);
        command.execute();
    }

    //遙控器返回命令
public class TeleController {
    //播放記錄
    List<Command> historyCommand = new ArrayList<Command>();

    //切換衛(wèi)視
    public void switchCommand(Command command) {
        historyCommand.add(command);
        command.execute();
    }
    public void back() {
        if (historyCommand.isEmpty()) {
            return;
        }
        int size = historyCommand.size();
        int preIndex = size-2<=0?0:size-2;

        //獲取上一個(gè)播放某衛(wèi)視的命令
        Command preCommand = historyCommand.remove(preIndex);
        preCommand.execute();
    }
}

 //創(chuàng)建一個(gè)電視機(jī)
        Television tv = new Television();
        //創(chuàng)建一個(gè)遙控器
        TeleController teleController = new TeleController();

        teleController.switchCommand(new CCTV1Command(tv));
        teleController.switchCommand(new CCTV2Command(tv));
       //模擬遙控器返回鍵
        teleController.back();
        teleController.back();
public class Context {
   private Strategy strategy;
 
   public Context(Strategy strategy){
      this.strategy = strategy;
   }
 
   public int executeStrategy(int num1, int num2){
      return strategy.doOperation(num1, num2);
   }
}

public interface Strategy {
   public int doOperation(int num1, int num2);
}
public class OperationAdd implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 + num2;
   }
}
public class OperationSubtract implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 - num2;
   }
}
public class OperationMultiply implements Strategy{
   @Override
   public int doOperation(int num1, int num2) {
      return num1 * num2;
   }
}

public class StrategyPatternDemo {
   public static void main(String[] args) {
      Context context = new Context(new OperationAdd());    
      System.out.println("10 + 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationSubtract());      
      System.out.println("10 - 5 = " + context.executeStrategy(10, 5));
 
      context = new Context(new OperationMultiply());    
      System.out.println("10 * 5 = " + context.executeStrategy(10, 5));
   }
}
  • 狀態(tài)模式(State Pattern):狀態(tài)對(duì)象依賴注入到context對(duì)象掸刊,context對(duì)象根據(jù)它的狀態(tài)改變而改變它的相關(guān)行為(可通過調(diào)用內(nèi)部的狀態(tài)對(duì)象實(shí)現(xiàn)相應(yīng)的具體行為)

  • 備忘錄模式(Memento Pattern):通過一個(gè)備忘錄類專門存儲(chǔ)對(duì)象狀態(tài)∮遥客戶通過備忘錄管理類管理備忘錄類忧侧。

  • 空對(duì)象模式(Null Object Pattern):創(chuàng)建一個(gè)未對(duì)該類做任何實(shí)現(xiàn)的空對(duì)象類石窑,該空對(duì)象類將無縫地使用在需要檢查空值的地方。不要為了屏蔽null而使用空對(duì)象蚓炬,應(yīng)保持用null松逊,遠(yuǎn)比用非null的值來替代“無值”要好。(慎用)

參考鏈接:http://www.reibang.com/p/234a156b0210

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末肯夏,一起剝皮案震驚了整個(gè)濱河市经宏,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌驯击,老刑警劉巖烁兰,帶你破解...
    沈念sama閱讀 218,122評(píng)論 6 505
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異徊都,居然都是意外死亡沪斟,警方通過查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,070評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門暇矫,熙熙樓的掌柜王于貴愁眉苦臉地迎上來主之,“玉大人,你說我怎么就攤上這事袱耽∩辈停” “怎么了?”我有些...
    開封第一講書人閱讀 164,491評(píng)論 0 354
  • 文/不壞的土叔 我叫張陵朱巨,是天一觀的道長史翘。 經(jīng)常有香客問我,道長冀续,這世上最難降的妖魔是什么琼讽? 我笑而不...
    開封第一講書人閱讀 58,636評(píng)論 1 293
  • 正文 為了忘掉前任,我火速辦了婚禮洪唐,結(jié)果婚禮上钻蹬,老公的妹妹穿的比我還像新娘。我一直安慰自己凭需,他們只是感情好问欠,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,676評(píng)論 6 392
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著粒蜈,像睡著了一般顺献。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上枯怖,一...
    開封第一講書人閱讀 51,541評(píng)論 1 305
  • 那天注整,我揣著相機(jī)與錄音,去河邊找鬼。 笑死肿轨,一個(gè)胖子當(dāng)著我的面吹牛寿冕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播椒袍,決...
    沈念sama閱讀 40,292評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼驼唱,長吁一口氣:“原來是場噩夢(mèng)啊……” “哼!你這毒婦竟也來了槐沼?” 一聲冷哼從身側(cè)響起曙蒸,我...
    開封第一講書人閱讀 39,211評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎岗钩,沒想到半個(gè)月后纽窟,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,655評(píng)論 1 314
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡兼吓,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,846評(píng)論 3 336
  • 正文 我和宋清朗相戀三年臂港,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片视搏。...
    茶點(diǎn)故事閱讀 39,965評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡审孽,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出浑娜,到底是詐尸還是另有隱情佑力,我是刑警寧澤,帶...
    沈念sama閱讀 35,684評(píng)論 5 347
  • 正文 年R本政府宣布筋遭,位于F島的核電站打颤,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏漓滔。R本人自食惡果不足惜编饺,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,295評(píng)論 3 329
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望响驴。 院中可真熱鬧透且,春花似錦、人聲如沸豁鲤。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,894評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽琳骡。三九已至锅论,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間日熬,已是汗流浹背棍厌。 一陣腳步聲響...
    開封第一講書人閱讀 33,012評(píng)論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留竖席,地道東北人耘纱。 一個(gè)月前我還...
    沈念sama閱讀 48,126評(píng)論 3 370
  • 正文 我出身青樓,卻偏偏與公主長得像毕荐,于是被迫代替她去往敵國和親束析。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,914評(píng)論 2 355

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