23種設計模式概要及易懂的例子

23種設計模式(分爲三大類)
 
由於內容是從有道雲筆記挪過來的,因此排版有點醜,若有不足或錯誤還望指點。。

注意,一些設計模式之間的(代碼)"形式"雖然相同或類似,可是"語義"是大相徑庭的。我的認爲設計模式提倡的是一種編碼思想,而不是規範。正則表達式

爲何要使用設計模式? 爲了代碼複用,增長可維護性

設計模式的六大原則

一、開閉原則(Open Close Principle)算法

開閉原則的意思是:對擴展開放,對修改關閉。在程序須要進行拓展的時候,不能去修改原有的代碼,實現一個熱插拔的效果。簡言之,是爲了使程序的擴展性好,易於維護和升級。想要達到這樣的效果,咱們須要使用接口和抽象類,後面的具體設計中咱們會提到這點。spring

二、里氏代換原則(Liskov Substitution Principle)sql

里氏代換原則是面向對象設計的基本原則之一。 里氏代換原則中說,任何基類能夠出現的地方,子類必定能夠出現。LSP 是繼承複用的基石,只有當派生類能夠替換掉基類,且軟件單位的功能不受到影響時,基類才能真正被複用,而派生類也可以在基類的基礎上增長新的行爲。里氏代換原則是對開閉原則的補充。實現開閉原則的關鍵步驟就是抽象化,而基類與子類的繼承關係就是抽象化的具體實現,因此里氏代換原則是對實現抽象化的具體步驟的規範。數據庫

三、依賴倒轉原則(Dependence Inversion Principle)編程

這個原則是開閉原則的基礎,具體內容:針對對接口編程,依賴於抽象而不依賴於具體。設計模式

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

這個原則的意思是:使用多個隔離的接口,比使用單個接口要好。它還有另一個意思是:下降類之間的耦合度。因而可知,其實設計模式就是從大型軟件架構出發、便於升級和維護的軟件設計思想,它強調下降依賴,下降耦合。數據結構

五、迪米特法則,又稱最少知道原則(Demeter Principle)架構

最少知道原則是指:一個實體應當儘可能少地與其餘實體之間發生相互做用,使得系統功能模塊相對獨立。

六、合成複用原則(Composite Reuse Principle)

合成複用原則是指:儘可能使用合成/聚合的方式,而不是使用繼承。

 

建立型模式(共五種)

工廠方法模式:定義一個建立對象的接口,讓其子類本身決定實例化哪個工廠類,工廠模式使其建立過程延遲到子類進行。
我的總結: 經過對象工廠靈活地生產多種對象
public class Factory_Method {
     
    public static void main(String[] args){
        AnimalsFactory animalsFactory = new AnimalsFactory();
        //經過工廠建立一個cat對象
        Animals cat = animalsFactory.getAnimals("cat");
        //經過工廠建立一個dog對象
        Animals dog = animalsFactory.getAnimals("dog");
        cat.name();  dog.name();
    }
}
 
interface Animals { //動物
    void name();
}
 
class Cat implements Animals{ //
    @Override
    public void name(){
        System.out.println("this is a cat");
    }
}
 
class Dog implements Animals{ //
    @Override
    public void name(){
        System.out.println("this is a dog");
    }
}
 
class AnimalsFactory { //動物工廠
    public Animals getAnimals(String name){
        if(name.equalsIgnoreCase("cat"))
            return new Cat();
        else if(name.equalsIgnoreCase("dog"))
            return new Dog();
        else 
            return null;
    }
}

 


抽象工廠模式:提供一個建立一系列相關或相互依賴對象的接口,而無需指定它們具體的類。
我的總結:工廠模式 >> 一種工廠,多種對象 ; 抽象工廠模式 >> 一種抽象工廠,多種工廠,每一個工廠又能夠生產多種對象
public class Abstract_Factory {
    //工廠生成器:生產具體的工廠
    public static AbstractFactory getFactory(String factoryName){
        if(factoryName.equalsIgnoreCase("animals"))
            return new AnimalsFactory();
        else if(factoryName.equalsIgnoreCase("others"))
            return new OthersFactory();
        else
            return null;
    }
    public static void main(String[] args){
        //生產動物工廠
        AbstractFactory animalsFactory = getFactory("animals");
        //經過動物工廠建立一個cat對象
        Animals cat = animalsFactory.getAnimals("cat");
        cat.name();
    }
}
 
interface Animals { //動物
    void name();
}
 
class Cat implements Animals{ //
    @Override
    public void name(){
        System.out.println("this is a cat");
    }
}
 
class AnimalsFactory extends AbstractFactory{ //動物工廠
    public Animals getAnimals(String name){
        if(name.equalsIgnoreCase("cat"))
            return new Cat();
        else 
            return null;
    }
    @Override
    public Object getObject() {
        return null;
    }
}
 
class OthersFactory extends AbstractFactory{ //其餘工廠
    public Object getObject() {
        return null;
    }
    @Override
    public Animals getAnimals(String name) {
        return null;
    }
}
 
abstract class AbstractFactory { //抽象工廠
    abstract public Animals getAnimals(String name);
    abstract public Object getObject();
}

 


單例模式:保證一個類僅有一個實例,並提供一個訪問它的全局訪問點。
我的總結:在類內部創造單一對象,經過設置構造方法權限,使類外部沒法再創造對象
public class Singleton {
     
    public static void main(String[] agrs){
        Earth earth = Earth.getEarth();
        System.out.println(earth.getAge());
    }
}
 
//建立單例對象的方式有多種,下面是比較經常使用的一種方式;按需求選擇合適方式。
class Earth {  //只容許建立一個對象的類
    //建立惟一對象
    private static Earth earth = new Earth();
    //構造函數訪問權限必須private
    private Earth(){}
    //獲取惟一對象
    public static Earth getEarth(){
        return earth;
    }
    private int age = 1000;
    public int getAge() {
        return age;
    }
}

 


建造者模式:將一個複雜的構建與其表示相分離,使得一樣的構建過程能夠建立不一樣的表示。
我的總結:將一些不會變的基本組件,經過builder,組合,構建複雜對象,實現分離
public class BuilderDemo {
 
    public static void main(String[] args) {
        PriceBuilder priceBuilder = new PriceBuilder();
        System.out.println("Car1和Car2:"+priceBuilder.Car1AndCar2());
        System.out.println("Car1和Bus:"+priceBuilder.Car1AndBus());
    }
}
//基本組件
interface Car {
}
//基本組件1
class Car1 implements Car{
    int price = 20;
}
//基本組件2
class Car2 implements Car{
    int price = 90;
}
//基本組件3
class Bus {
    int price = 500;
}
class PriceBuilder {
    //car1和car2的總價格
    public int Car1AndCar2() {
        int priceOfCar1 = new Car1().price;
        int priceOfCar2 = new Car2().price;
        return priceOfCar1+priceOfCar2;
    }
    //car1和bus的總價格
    public int Car1AndBus() {
        int priceOfCar1 = new Car1().price;
        int priceOfBus = new Bus().price;
        return priceOfCar1+priceOfBus;
    }
}

 


原型模式:用原型實例指定建立對象的種類,而且經過拷貝這些原型建立新的對象。
我的總結: 將對象複製了一份並返還給調用者,對象需繼承Cloneable並重寫clone()方法
public class Prototype implements Cloneable{
 
    private String message = "hello";
     
    public Object clone() throws CloneNotSupportedException{
        Prototype proto = (Prototype) super.clone();
        //操做克隆對象
        proto.message += " world!";
        return proto; 
    }
     
    public static void main(String[] args) throws CloneNotSupportedException {
        Prototype p = (Prototype)new Prototype().clone();
        //操做克隆對象
        System.out.println(p.message);
    }
}

 

 

 

結構型模式(共七種)

適配器模式:將一個類的接口轉換成客戶但願的另一個接口。適配器模式使得本來因爲接口不兼容而不能一塊兒工做的那些類能夠一塊兒工做。
我的總結:銜接兩個不兼容、獨立的接口的功能,使得它們可以一塊兒工做。適配器起中介做用。
public class Adapter {
 
    public static void main(String[] args) {
        //兼容了高級功能的普通播放器
        Player player = new Player();
        player.play();
    }
}
//普通的播放器
interface MediaPlayer {
    public void play();
}
//高級的播放器
interface AdvanceMediaPlayer {
    public void playVideo();
}
//視頻播放器(高級的播放器)
class VideoPlayer implements AdvanceMediaPlayer {
    @Override
    public void playVideo(){
        System.out.println("play video!");
    }
}
//適配器(銜接了普通播放器與高級播放器這兩個獨立接口的功能)
class MediaAdapter implements MediaPlayer {
    AdvanceMediaPlayer advanceMediaPlayer;
    public MediaAdapter() {
        advanceMediaPlayer = new VideoPlayer();
    }
    @Override
    public void play() {
        advanceMediaPlayer.playVideo();
    }
}
//普通播放器
class Player implements MediaPlayer {
    //兼容高級播放器的適配器
    MediaAdapter mediaAdapter = new MediaAdapter();
 
    @Override
    public void play() {
        mediaAdapter.play();
    }
}

 


裝飾器模式:動態地給一個對象添加一些額外的職責。就增長功能來講,裝飾器模式相比生成子類更爲靈活。
我的總結:建立類的裝飾類,對被裝飾類加強功能。裝飾模式是繼承的一個替代模式。
public class Decorator {
 
    public static void main(String[] args) {
        Animals dog = new AnimalsDecorator(new Dog());
        dog.run();
    }
}
interface Animals {
    public void run();
}
//被裝飾類
class Dog implements Animals{
    @Override
    public void run() {
        System.out.println("dog run!");
    }
}
//裝飾類
class AnimalsDecorator implements Animals {
    private Animals animals;
    //動態裝飾,參數爲Animals接口,傳入什麼實現就裝飾什麼實現
    //繼承不能作到這一點,繼承的功能是靜態的,不能動態增刪。
    public AnimalsDecorator(Animals animals) {
        this.animals = animals;
    }
    @Override
    //裝飾run()方法
    public void run() {
        animals.run();
        System.out.println("fast!");
    }
}

 

 

代理模式:爲其餘對象提供一種代理以控制對這個對象的訪問。
我的總結:建立類的代理類,間接訪問被代理類的過程當中對其功能加以控制,例如在某個函數執行先後添加額外功能。(代理例子:買火車票不必定在火車站買,也能夠去代售點)。 和裝飾器模式的區別:裝飾器模式爲了加強功能,而代理模式是爲了加以控制,"形式"雖然類似,"語義"卻大相徑庭"。起中介做用
public class Proxy {
 
    public static void main(String[] args) {
        Animals dog = new DogProxy(new Dog());
        dog.run();
    }
}
interface Animals {  
    public void run();  
}  
class Dog implements Animals {  
    @Override  
    public void run() {  
        System.out.println("run!");  
    }  
}  
//經過代理類,在被代理類的run()方法執行先後添加額外的功能
class DogProxy implements Animals {  
    private Animals animals;  
    public DogProxy(Animals animals){  
        super();  
        this.animals = animals;
    }  
    @Override  
    public void run() {  
        before();  
        animals.run();  
        atfer();  
    }  
    private void atfer() {  
        System.out.println("after run!");  
    }  
    private void before() {  
        System.out.println("before run!");  
    }  
}  

 

 

外觀模式:爲子系統中的一組接口提供一個一致的界面,外觀模式定義了一個高層接口,這個接口使得這一子系統更加容易使用。
我的總結:在客戶端和複雜系統之間再加一層,在這一層中將調用順序、依賴關係等處理好。提供一個容易使用的外觀層。
public class Facade {
 
    public static void main(String[] args) {
        Computer computer = new Computer();
        computer.put();
    }
}
class CPU {
    public void work(){
        //複雜的操做
        System.out.println("CPU is working!");
    }
}
class Disk {
    public void put(){
        //複雜的操做
        System.out.println("put in disk!");
    }
}
//外觀類,隱藏了系統的複雜性,提供簡化的方法(訪問系統的接口)
//客戶端不須要知道系統內部的複雜聯繫
class Computer {
    private CPU cpu;
    private Disk disk;
     
    public Computer(){
        cpu = new CPU();
        disk = new Disk();
    }
    public void work(){
        cpu.work();
    }
    public void put(){
        disk.put();
    }
}

 

 

橋接模式:將抽象部分與實現部分分離,使它們均可以獨立的變化。
我的總結:經過對Bridge類的調用,實現了對同一接口下不一樣實現類的調用;創建一個繼承於同一抽象的不一樣實現類之間的關聯關係,這個關係由Bridge類橋接起來。
public class Bridge {
 
    public static void main(String[] args) {
        AnimalsBridge bridge = new AnimalsBridge(new Dog());
        bridge.method();
    }
}
//接口
interface Animals {  
    public void method();  
}
//實現1
class Cat implements Animals {  
    @Override  
    public void method() {  
        System.out.println("this is cat!");  
    }  
} 
//實現2
class Dog implements Animals {  
    @Override  
    public void method() {  
        System.out.println("this is dog!");  
    }  
}  
//將Animals接口下的不一樣實現,
//經過橋接模式使它們在抽象層創建一個關聯關係。
//實現之間獨立變化,減小耦合
class AnimalsBridge {
    private Animals animals;
    public AnimalsBridge(Animals animals) {
        this.animals = animals;
    }
    public void method(){
        animals.method();
    }
}

 

 

組合模式:將對象組合成樹形結構以表示"部分-總體"的層次結構。組合模式使得用戶對單個對象和組合對象的使用具備一致性。
我的總結:建立了一個包含本身對象組的類,並提供修改對象組的方法。應用場景,如樹形菜單,文件、文件夾的管理。
public class Composite {
 
    public static void main(String[] args) {
        Person person = new Person("小明");
        person.addFriends(new Person("小紅"));
        person.addFriends(new Person("小白"));
        System.out.println(person.getFriends());
    }
}
class Person {
    private String name;
    //包含本身的對象組
    private List<Person> friends = new ArrayList<Person>();
     
    public Person(String name){
        this.name = name;
    }
    public Person addFriends(Person p){
        friends.add(p);
        return this;
    }
    public String getName(){
        return this.name;
    }
    public List<Person> getFriends(){
        return this.friends;
    }
    public String toString(){
        return this.name;
    }
}

 


享元模式:運用共享技術有效地支持大量細粒度的對象。
我的總結:重用現有的同類對象,若未找到匹配的對象,則建立新對象。例如,數據庫的鏈接池。減小對象的建立,下降系統內存,提升效率。
public class Flyweight {
 
    public static void main(String[] args) {
        //red Circle默認存在,因此拿的時候不用new
        Circle circle = CircleFactory.getCircle("red");
        circle.draw();
        for(int i=0;i<2;i++) {
            //第一次拿的時候須要new green Circle,第二次拿的時候不用new
            circle = CircleFactory.getCircle("green");
            circle.draw();
        }
    }
}
class Circle {
    private String color;
    public Circle(String color){
        this.color = color;
    }
    public void draw(){
        System.out.println(color+" Circle!");
    }
}
class CircleFactory {
    private static final HashMap<String, Circle> circleMap = new HashMap<String, Circle>();
    static {
        //初始化,存放red Circle
        circleMap.put("red", new Circle("red"));
    }
    public static Circle getCircle(String color) {
        Circle circle = (Circle)circleMap.get(color);
        //Map若是不存在該顏色的Circle,則新建
        if(circle == null) {
            circle = new Circle(color);
            circleMap.put(color, circle);
            System.out.println("new a circle of color: "+color);
        }
        //若是存在,則返回Map中的對象
        return circle;
    }
}

 


 

行爲型模式(共十一種)

策略模式:定義一系列的算法,把它們一個個封裝起來, 而且使它們可相互替換。
我的總結:統一接口下的一系列算法類(多種策略),用一個類將其封裝起來,使它們(多種策略)可動態切換。 和工廠模式的區別:工廠模式是建立型模式,是爲了建立不一樣對象;而策略模式是行爲模式,爲了選擇不一樣的行爲。
 
public class Strategy {
 
    public static void main(String[] args) {
        OperationStrategy operationStrategy = new OperationStrategy(new OperationAdd());
        operationStrategy.executeStrategy(15, 21);
    }
}
interface Operation{
    public void doOperation(int a, int b);
}
//策略1
class OperationAdd implements Operation{
    public void doOperation(int a, int b){
        System.out.println(a+"+"+b+"="+(a+b));
    }
}
//策略2
class OperationMultiply implements Operation{
    public void doOperation(int a, int b){
        System.out.println(a+"*"+b+"="+(a*b));
    }
}
//封裝一系列策略,可任意替換策略(實現同一個接口)
class OperationStrategy{
    private Operation operation;
    public OperationStrategy(Operation operation){
        this.operation = operation;
    }
    //執行策略
    public void executeStrategy(int a, int b){
        operation.doOperation(a, b);
    }
}

 

 

模板方法模式:定義一個操做中的算法的骨架,而將一些步驟延遲到子類中。模板方法使得子類能夠不改變一個算法的結構便可重定義該算法的某些特定步驟。
我的總結:將一些固定步驟、固定邏輯的方法封裝成模板方法。調用模板方法便可完成那些特定的步驟。例如,spring中對Hibernate的事務管理,開啓session、關閉session等固定步驟不需重複寫,直接丟給一個實體保存。
public class Template {
 
    public static void main(String[] args) {
        Game game = new FootballGame();
        game.play();
    }
}
abstract class Game {
    //步驟1,初始化遊戲
    abstract void initialize();
    //步驟2,開始遊戲
    abstract void startPlay();
    //,步驟3,結束遊戲
    abstract void endPlay();
    //主方法,模板方法,設置爲final,在抽象類中實現
    public final void play() {
        initialize();
        startPlay();
        endPlay();
    }
}
class FootballGame extends Game {
    @Override
    void initialize() {
        System.out.println("Football Game Initialized! Start playing.");
    }
    @Override
    void startPlay() {
        System.out.println("Football Game Started. Enjoy the game!");
    }
    @Override
    void endPlay() {
        System.out.println("Football Game Finished!");
    }
}

 

 

觀察者模式:定義對象間的一種一對多的依賴關係,當一個對象的狀態發生改變時,全部依賴於它的對象都獲得通知並被自動更新。
我的總結:一個對象(被觀察者)狀態變化時,通知全部依賴於它的對象(觀察者);這種依賴方式具備雙向性:觀察者指定被觀察的對象,或者被觀察對象添加觀察者,下面例子採用後者方式
public class Observer {
 
    public static void main(String[] args) {
        Subject subject = new Subject();
        subject.addSubjectObserver(new Observer1());
        subject.addSubjectObserver(new Observer2());
        subject.setState(1);
    }
}
 
class Subject {
    //一對多關係,多個該類的觀察者
    private List<SubjectObserver> subjectObservers = new ArrayList<SubjectObserver>();
    //狀態(被觀察),發生變化時通知全部觀察者
    private int state;
    public void setState(int state) {
        this.state = state;
        //改變狀態,通知全部觀察者
        notifyAllSubjectObservers();
    }
    public void addSubjectObserver(SubjectObserver subjectObserver) {
        subjectObservers.add(subjectObserver);
    }
    //通知全部觀察者
    public void notifyAllSubjectObservers() {
        for (SubjectObserver subjectObserver : subjectObservers) {
            subjectObserver.alert();
        }
    }
}
abstract class SubjectObserver {
    protected Subject subject;
    public abstract void alert();
}
//觀察者1
class Observer1 extends SubjectObserver {
    @Override
    public void alert() {
        System.out.println("Observer1: subject is changed!");
    }
}
//觀察者2
class Observer2 extends SubjectObserver {
    @Override
    public void alert() {
        System.out.println("Observer2: subject is changed!");
    }
}

 

 

迭代器模式:提供一種方法順序訪問一個聚合對象中各個元素, 而又無須暴露該對象的內部表示。
我的總結:Java中的iterator的簡單實現原理。將聚合類中遍歷各個元素的行爲分離出來,封裝成迭代器,讓迭代器來處理遍歷的任務;使簡化聚合類,同時又不暴露聚合類的內部。
 
public class IteratorDemo {
 
    public static void main(String[] args) {
        MyContainer myContainer = new MyContainer();
        Iterator iterator = myContainer.getIterator();
        while(iterator.hashNext())
            System.out.println(iterator.next());
    }
}
//迭代器接口
interface Iterator {
    public boolean hashNext();
    public Object next();
}
//容器接口
interface Container {
    public Iterator getIterator();
}
//自定義容器(聚合類)
class MyContainer implements Container{
    public String names[] = {"Robert" , "John" ,"Julie" , "Lora"};
    @Override
    public Iterator getIterator(){
        return new MyIterator();
    }
    //自定義迭代器,迭代器類定義爲容器類的內部類
    private class MyIterator implements Iterator{
        int index = 0;
        //自定義遍歷規則
        @Override
        public boolean hashNext(){
            if(index < names.length)
                return true;
            return false;
        }
        @Override
        public Object next(){
            if(this.hashNext())
                return names[index++];
            return null;
        }
    }
}

 

 

 

責任鏈模式:避免請求發送者與接收者耦合在一塊兒,讓多個對象都有可能接收請求,將這些對象鏈接成一條鏈,而且沿着這條鏈傳遞請求,直到有對象處理它爲止。
我的總結:在Handler類裏面聚合本身,造成一條Handler鏈(或樹、環等),而且能夠將請求往下一個Handler傳遞(只容許傳給另外一個,而不容許傳給多個)。例子:Struts攔截器,Filter過濾器
public class Chain_of_Responsibility {
 
    public static void main(String[] args) {
        ResponsibilityHandler handler1 = new ResponsibilityHandler("handler1");
        ResponsibilityHandler handler2 = new ResponsibilityHandler("handler2");
        ResponsibilityHandler handler3 = new ResponsibilityHandler("handler3");
        handler1.setResponsibilityHandler(handler2);
        handler2.setResponsibilityHandler(handler3);
        handler1.operator();//操做請求會沿着這條鏈傳遞下去,
    }
}
//責任處理器/接收器
class ResponsibilityHandler {
    //聚合本身,構成一條責任鏈
    private ResponsibilityHandler responsibilityHandler = null;
    private String name;
    public ResponsibilityHandler(String name){
        this.name = name;
    }
    public ResponsibilityHandler next(){
        return this.responsibilityHandler;
    }
    public void setResponsibilityHandler(ResponsibilityHandler responsibilityHandler){
        this.responsibilityHandler = responsibilityHandler;
    }
    public void operator(){
        System.out.println(name+" is handler!");
        if(this.next() != null){
            //將請求發送到下一個責任接收器
            next().operator();
        }
    }
}

 

 

命令模式:將一個請求封裝成一個對象,從而使您能夠用不一樣的請求對客戶進行參數化。
我的總結:三種角色(調用者→接受者→命令);解耦行爲請求者和行爲實現着,實現請求和執行分開;調用者選擇命令發佈,命令指定執行者。
public class CommandDemo {
 
    public static void main(String[] args) {
        Receiver receiver = new Receiver("小明");
        //指定命令的執行者
        Command shootCommand = new ShootCommand(receiver);
        Command otherCOmmand = new OtherCommand(receiver);
        Invoker invoker = new Invoker();
        invoker.addCommands(shootCommand);
        invoker.addCommands(otherCOmmand);
        invoker.sendCommands();
    }
}
//命令
interface Command {
    public void execute();
}
//射擊命令
class ShootCommand implements Command{
    private Receiver receiver;
    public ShootCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        System.out.println("shootCommand is execute:");
        receiver.action();
    }
}
//其餘命令
class OtherCommand  implements Command{
    private Receiver receiver;
    public OtherCommand(Receiver receiver){
        this.receiver = receiver;
    }
    public void execute(){
        System.out.println("otherCommand is execute:");
        receiver.action();
    }
}
//命令接受者(士兵)
class Receiver {
    public String name;
    public Receiver(String name){
        this.name = name;
    }
    //行動,執行命令
    public void action(){
        System.out.println(name+" received the command!");
    }
}
//命令調用者(司令官)
class Invoker {
    private List<Command> commandList = new ArrayList<Command>();
    public void addCommands(Command command){
        this.commandList.add(command);
    }
    //發出命令
    public void sendCommands(){
        for(Command command : commandList){
            command.execute();
            System.out.println();
        }
        commandList.clear();
    }
}

 

 

備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,並在該對象以外保存這個狀態。
我的總結:建立一個備忘錄類,用來存儲原始類的信息;同時建立備忘錄倉庫類,用來存儲備忘錄類,固然,原始類與備忘錄類的對應關係要處理好。
 
public class MementoDemo {
 
    public static void main(String[] args) {
        //待備份的類
        Originator originator = new Originator();
        originator.setState("123");
        System.out.println("初始化的狀態爲:"+originator.getState());
        MementoStorage mementoStorage = new MementoStorage();
        mementoStorage.add(originator.createMemento());
        originator.setState("321");
        System.out.println("修改後的狀態爲:"+originator.getState());
        originator.restoreMemento(mementoStorage.get(0));
        System.out.println("還原後的狀態爲:"+originator.getState());
    }
}
//備忘錄類
class Memento {
    private String state;
    public Memento(String state){
        this.state = state;
    }
    public String getState(){
        return this.state;
    }
}
//備忘錄類倉庫,備忘錄管理類
class MementoStorage {
    private List<Memento> mementoList = new ArrayList<Memento>();
    public void add(Memento state){
        mementoList.add(state);
    }
    public Memento get(int index){
        return mementoList.get(index);
    }
}
//原始類
class Originator {
    private String state;
    public void setState(String state){
        this.state = state;
    }
    public String getState(){
        return this.state;
    }
    //建立備份
    public Memento createMemento(){
        //把須要備份的信息所有存儲到備份類中。
        return new Memento(state);
    }
    //還原備份
    public void restoreMemento(Memento memento){
        //把備份類中存儲的信息還原
        state = memento.getState();
    }
}

 

 

 

狀態模式:容許對象在內部狀態發生改變時改變它的行爲,對象看起來好像修改了它的類。
我的總結:對象具備多種狀態,且每種狀態具備特定的行爲;應用場景: 行爲隨狀態改變而改變的場景。代碼形式彷佛也和哪一種設計模式類似,仍是那句話,設計模式提倡的是思想,而不是形式。
public class StateDemo {
 
    public static void main(String[] args) {
        QQContext context = new QQContext();
        //設置狀態,不一樣的狀態對應不一樣的行爲
        context.setState(new OnlineState());
        context.getState().getMessage();
    }
}
interface State{
    public void getMessage();
}
//在線狀態(狀態對象)
class OnlineState implements State{
    //在線狀態下的行爲
    public void getMessage(){
        System.out.println("在線中,對好友可見!");
    }
}
//隱身狀態(狀態對象)
class StealthState implements State{
    //隱身狀態下的行爲
    public void getMessage(){
        System.out.println("隱身中,對好友不可見!");
    }
}
//QQ的登錄狀態類
class QQContext {
    private State state;
 
    public State getState() {
        return state;
    }
    public void setState(State state) {
        this.state = state;
    }
}

 

 

訪問者模式:主要將數據結構與數據操做分離。
我的總結:在被訪問的類裏面加一個對外提供接待訪問者的接口(以下面例子的accept()方法)。訪問者封裝了對被訪問者結構的一些雜亂操做,避免這些操做"污染"被訪問者,解耦結構與算法,同時具備優秀的擴展性。
public class Visitor {
 
    public static void main(String[] args) {
        Computer computer = new Computer("myComputer");
        //computer接受computerVisitor的訪問
        computer.accept(new ComputerVisitor());
    }
}
//被訪問者
class Computer {
    private String computerName;
    public String getComputerName(){
        return computerName;
    }
    public Computer(String computerName){
        this.computerName = computerName;
    }
    //提供接待訪問者的接口
    public void accept(ComputerVisitor computerVisitor){
        //訪問者訪問自身
        computerVisitor.visit(this);
    }
}
//訪問者
class ComputerVisitor {
    //訪問Computer類,將被訪問者的引用傳入訪問者
    public void visit(Computer computer){
        System.out.println("訪問"+computer+"的name屬性:"+computer.getComputerName());
    }
}

 

 

中介者模式:用一箇中介對象來封裝一系列的對象交互,中介者使各對象不須要顯式地相互引用,從而使其耦合鬆散,並且能夠獨立地改變它們之間的交互。
我的總結:中介者對象,用來封裝關聯對象之間的交互操做,使關聯對象之間耦合度鬆散;例如,MVC模式中"控制器"就是"模型"和"視圖"的中介者;與適配器模式的區別:適配器模式爲了橋接互不兼容的接口,中介者爲了分離原始結構和交互行爲。
 
public class Mediator {
 
    public static void main(String[] args) {
        User1 user1 = new User1("小明");
        User2 user2 = new User2("小紅");
        UserMediator userMediator = new UserMediator(user1,user2);
        userMediator.introduceYourselves();
    }
}
class User1 {
    private String name;
    public String getName(){
        return name;
    }
    public User1(String name){
        this.name = name;
    }
}
class User2 {
    private String name;
    public String getName(){
        return name;
    }
    public User2(String name){
        this.name = name;
    }
}
//中介者,用來封裝User1與User2的交互操做
class UserMediator {
    private User1 user1;
    private User2 user2;
    //將User1與User2傳入它們的中介者
    public UserMediator(User1 user1, User2 user2){
        this.user1 = user1; this.user2 = user2;
    }
    public void introduceYourselves(){
        System.out.println("Hello "+user1.getName()+",I'm "+user2.getName());
        System.out.println("Hi "+user2.getName()+",My name is "+user1.getName());
    }
}

 

 

 

解釋器模式:給定一個語言,定義它的文法表示,並定義一個解釋器,這個解釋器使用該標識來解釋語言中的句子。
我的總結:本身定義一種語言或表達式(附對應的解釋器),用來表示一些複雜的頻繁發生的行爲。例如:正則表達式的解釋,sql語句的解釋。使用場景極少,會引發效率、性能、維護等問題。
public class Interpreter {
 
    public static void main(String[] args) {
        Context context = new Context();
        //建立自定義變量
        Variable a = new Variable();
        Variable b = new Variable();
        //建立常量 3
        Constant c = new Constant(3);
        //給變量賦值
        context.put(a, 5).put(b, 1);
        //構建語法樹(自定義表達式:a+b+3)
        Expression exp = new Add(new Add(a,b), c);
        //解釋表達式a+b+3
        int result = exp.interpret(context);
        System.out.println("a+b+3 = "+result);
    }
}
//表達式(全部表達式角色繼承該接口,自帶解釋器)
interface Expression {
    //解釋器,解釋角色所需參數存儲在Context類中
    public int interpret(Context context);
}
//構件環境類,包含解釋器以外的一些全局信息,通常是 HashMap。
class Context {
    private Map<Variable,Integer> valueMap = new HashMap<Variable,Integer>();
    public Context put(Variable x, int y){
        valueMap.put(x, y);
        return this;
    }
    public int get(Variable x){
        int value = (Integer) valueMap.get(x);
        return value;
    }
}
//終結符表達式角色--常量
class Constant implements Expression{
    private int a;
    public Constant(int a){
        this.a = a;
    }
    public int interpret(Context context){
        return a;
    }
}
//終結符表達式角色--變量
class Variable implements Expression{
    public int interpret(Context context){
        return context.get(this);
    }
}
//非終結符表達式角色--運算符(+)
class Add implements Expression {
    private Expression x, y;
    public Add(Expression x, Expression y){
        this.x = x; this.y = y;
    }
    public int interpret(Context context){
        return x.interpret(context) + y.interpret(context);
    }
}
相關文章
相關標籤/搜索