Java設計模式


參考:https://www.cnblogs.com/pony1223/p/7608955.html

             https://www.cnblogs.com/zhaojinyan/p/9401010.html

java的設計模式大體上分為三大類

  • 創建型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。
  • 結構型模式(7種):適配器模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。
  • 行為型模式(11種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、解釋器模式。

設計模式遵循的原則有6個:

1、開閉原則(Open Close Principle)

  對擴展開放,對修改關閉

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

  只有當衍生類可以替換掉基類,軟件單位的功能不受到影響時,基類才能真正被復用,而衍生類也能夠在基類的基礎上增加新的行為。

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

  這個是開閉原則的基礎,對接口編程,依賴於抽象而不依賴於具體。

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

  使用多個隔離的借口來降低耦合度。

5、迪米特法則(最少知道原則)(Demeter Principle)

  一個實體應當盡量少的與其他實體之間發生相互作用,使得系統功能模塊相對獨立。

6、合成復用原則(Composite Reuse Principle)

  原則是盡量使用合成/聚合的方式,而不是使用繼承。繼承實際上破壞了類的封裝性,超類的方法可能會被子類修改。

1. 工廠模式(Factory Method)

  常用的工廠模式是靜態工廠,利用static方法,作為一種類似於常見的工具類Utils等輔助效果,一般情況下工廠類不需要實例化。

  

interface food{}

class A implements food{}
class B implements food{}
class C implements food{}

public class StaticFactory {

    private StaticFactory(){}
    
    public static food getA(){  return new A(); }
    public static food getB(){  return new B(); }
    public static food getC(){  return new C(); }
}

class Client{
    //客戶端代碼只需要將相應的參數傳入即可得到對象
    //用戶不需要了解工廠類內部的邏輯。
    public void get(String name){
        food x = null ;
        if ( name.equals("A")) {
            x = StaticFactory.getA();
        }else if ( name.equals("B")){
            x = StaticFactory.getB();
        }else {
            x = StaticFactory.getC();
        }
    }
}

 

2. 抽象工廠模式(Abstract Factory)

  一個基礎接口定義了功能,每個實現接口的子類就是產品,然后定義一個工廠接口,實現了工廠接口的就是工廠,這時候,接口編程的優點就出現了,我們可以新增產品類(只需要實現產品接口),只需要同時新增一個工廠類,客戶端就可以輕松調用新產品的代碼。

  抽象工廠的靈活性就體現在這里,無需改動原有的代碼,畢竟對於客戶端來說,靜態工廠模式在不改動StaticFactory類的代碼時無法新增產品,如果采用了抽象工廠模式,就可以輕松的新增拓展類。

  實例代碼:

3. 單例模式(Singleton)

   在內部創建一個實例,構造器全部設置為private,所有方法均在該實例上改動,在創建上要注意類的實例化只能執行一次,可以采用許多種方法來實現,如Synchronized關鍵字,或者利用內部類等機制來實現。

  

public class Singleton {
    private Singleton(){}

    private static class SingletonBuild{
        private static Singleton value = new Singleton();
    }

    public Singleton getInstance(){  return  SingletonBuild.value ;}
    
}

 

4.建造者模式(Builder)

  在了解之前,先假設有一個問題,我們需要創建一個學生對象,屬性有name,number,class,sex,age,school等屬性,如果每一個屬性都可以為空,也就是說我們可以只用一個name,也可以用一個school,name,或者一個class,number,或者其他任意的賦值來創建一個學生對象,這時該怎么構造?

  難道我們寫6個1個輸入的構造函數,15個2個輸入的構造函數.......嗎?這個時候就需要用到Builder模式了。給個例子,大家肯定一看就懂:

 

public class Builder {

    static class Student{
        String name = null ;
        int number = -1 ;
        String sex = null ;
        int age = -1 ;
        String school = null ;

     //構建器,利用構建器作為參數來構建Student對象
        static class StudentBuilder{
            String name = null ;
            int number = -1 ;
            String sex = null ;
            int age = -1 ;
            String school = null ;
            public StudentBuilder setName(String name) {
                this.name = name;
                return  this ;
            }

            public StudentBuilder setNumber(int number) {
                this.number = number;
                return  this ;
            }

            public StudentBuilder setSex(String sex) {
                this.sex = sex;
                return  this ;
            }

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

            public StudentBuilder setSchool(String school) {
                this.school = school;
                return  this ;
            }
            public Student build() {
                return new Student(this);
            }
        }

        public Student(StudentBuilder builder){
            this.age = builder.age;
            this.name = builder.name;
            this.number = builder.number;
            this.school = builder.school ;
            this.sex = builder.sex ;
        }
    }

    public static void main( String[] args ){
        Student a = new Student.StudentBuilder().setAge(13).setName("LiHua").build();
        Student b = new Student.StudentBuilder().setSchool("sc").setSex("Male").setName("ZhangSan").build();
    }
}

 

5. 原型模式(Protype)

原型模式就是講一個對象作為原型,使用clone()方法來創建新的實例。

public class Prototype implements Cloneable{

    private String name;

    public String getName() {
        return name;
    }

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

    @Override
    protected Object clone()   {
        try {
            return super.clone();
        } catch (CloneNotSupportedException e) {
            e.printStackTrace();
        }finally {
            return null;
        }
    }

    public static void main ( String[] args){
        Prototype pro = new Prototype();
        Prototype pro1 = (Prototype)pro.clone();
    }
}

 

此處使用的是淺拷貝,關於深淺拷貝,大家可以另行查找相關資料。

6.適配器模式(Adapter)

適配器模式的作用就是在原來的類上提供新功能。主要可分為3種:

  • 類適配:創建新類,繼承源類,並實現新接口,例如 
    class  adapter extends oldClass  implements newFunc{}
  • 對象適配:創建新類持源類的實例,並實現新接口,例如 
    class adapter implements newFunc { private oldClass oldInstance ;}
  • 接口適配:創建新的抽象類實現舊接口方法。例如 
    abstract class adapter implements oldClassFunc { void newFunc();}

7.裝飾模式(Decorator)

 給一類對象增加新的功能,裝飾方法與具體的內部邏輯無關。例如:

interface Source{ void method();}
public class Decorator implements Source{

    private Source source ;
    public void decotate1(){
        System.out.println("decorate");
    }
    @Override
    public void method() {
        decotate1();
        source.method();
    }
}

 

8.代理模式(Proxy)

客戶端通過代理類訪問,代理類實現具體的實現細節,客戶只需要使用代理類即可實現操作。

這種模式可以對舊功能進行代理,用一個代理類調用原有的方法,且對產生的結果進行控制。

interface Source{ void method();}

class OldClass implements Source{
    @Override
    public void method() {
    }
}

class Proxy implements Source{
    private Source source = new OldClass();

    void doSomething(){}
    @Override
    public void method() {
        new Class1().Func1();
        source.method();
        new Class2().Func2();
        doSomething();
    }
}

 

9.外觀模式(Facade)

為子系統中的一組接口提供一個一致的界面,定義一個高層接口,這個接口使得這一子系統更加容易使用。這句話是百度百科的解釋,有點難懂,但是沒事,看下面的例子,我們在啟動停止所有子系統的時候,為它們設計一個外觀類,這樣就可以實現統一的接口,這樣即使有新增的子系統subSystem4,也可以在不修改客戶端代碼的情況下輕松完成。

public class Facade {
    private subSystem1 subSystem1 = new subSystem1();
    private subSystem2 subSystem2 = new subSystem2();
    private subSystem3 subSystem3 = new subSystem3();
    
    public void startSystem(){
        subSystem1.start();
        subSystem2.start();
        subSystem3.start();
    }
    
    public void stopSystem(){
        subSystem1.stop();
        subSystem2.stop();
        subSystem3.stop();
    }
}

 

10.橋接模式(Bridge)

這里引用下http://www.runoob.com/design-pattern/bridge-pattern.html的例子。Circle類將DrwaApi與Shape類進行了橋接,代碼:

interface DrawAPI {
    public void drawCircle(int radius, int x, int y);
}
class RedCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: red, radius: "
                + radius +", x: " +x+", "+ y +"]");
    }
}
class GreenCircle implements DrawAPI {
    @Override
    public void drawCircle(int radius, int x, int y) {
        System.out.println("Drawing Circle[ color: green, radius: "
                + radius +", x: " +x+", "+ y +"]");
    }
}

abstract class Shape {
    protected DrawAPI drawAPI;
    protected Shape(DrawAPI drawAPI){
        this.drawAPI = drawAPI;
    }
    public abstract void draw();
}

class Circle extends Shape {
    private int x, y, radius;

    public Circle(int x, int y, int radius, DrawAPI drawAPI) {
        super(drawAPI);
        this.x = x;
        this.y = y;
        this.radius = radius;
    }

    public void draw() {
        drawAPI.drawCircle(radius,x,y);
    }
}

//客戶端使用代碼
Shape redCircle = new Circle(100,100, 10, new RedCircle());
Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();

 

11.組合模式(Composite)

 組合模式是為了表示那些層次結構,同時部分和整體也可能是一樣的結構,常見的如文件夾或者樹。舉例:

abstract class component{}

class File extends  component{ String filename;}

class Folder extends  component{
    component[] files ;  //既可以放文件File類,也可以放文件夾Folder類。Folder類下又有子文件或子文件夾。
    String foldername ;
    public Folder(component[] source){ files = source ;}
    
    public void scan(){
        for ( component f:files){
            if ( f instanceof File){
                System.out.println("File "+((File) f).filename);
            }else if(f instanceof Folder){
                Folder e = (Folder)f ;
                System.out.println("Folder "+e.foldername);
                e.scan();
            }
        }
    }
    
}

 

12.享元模式(Flyweight)

使用共享對象的方法,用來盡可能減少內存使用量以及分享資訊。通常使用工廠類輔助,例子中使用一個HashMap類進行輔助判斷,數據池中是否已經有了目標實例,如果有,則直接返回,不需要多次創建重復實例。

abstract class flywei{ }

public class Flyweight extends flywei{
    Object obj ;
    public Flyweight(Object obj){
        this.obj = obj;
    }
}

class  FlyweightFactory{
    private HashMap<Object,Flyweight> data;

    public FlyweightFactory(){ data = new HashMap<>();}

    public Flyweight getFlyweight(Object object){
        if ( data.containsKey(object)){
            return data.get(object);
        }else {
            Flyweight flyweight = new Flyweight(object);
            data.put(object,flyweight);
            return flyweight;
        }
    }
}

 

--------------------------------------------------------------------------------------------------------------------------------------------------------

12.觀察者模式

subject:

 

package com.example.springbootstarterhello.observe;

import jdk.internal.dynalink.beans.StaticClass;

import java.util.Observable;

public class Subject extends Observable {
    private String name;
    private String  sex;

    public String getName() {
        return name;
    }

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

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }


    public void show(){
        setChanged();
        notifyObservers(new Data(getName(),getSex()));

    }
    public void setData(String name, String sex){
        this.name = name;
        this.sex = sex;
        show();
    }

    public class Data{
        public String name;
        public  String sex;

        public Data(String name, String sex) {
            this.name = name;
            this.sex = sex;
        }
    }
}

 

observer:

 

package com.example.springbootstarterhello.observe;

import java.util.ArrayList;
import java.util.List;
import java.util.Observable;

public class Observer1 implements java.util.Observer {
    private String name;
    private String  sex;
    @Override
    public void update(Observable o, Object arg) {
        this.name = ((Subject.Data) (arg)).name;
        this.sex = ((Subject.Data) (arg)).sex;
        System.out.println(name+"---1----"+sex);
    }


}

 

package com.example.springbootstarterhello.observe;

import java.util.Observable;

public class Observer2 implements java.util.Observer {
    private String name;
    private String  sex;

    @Override
    public void update(Observable o, Object arg) {
        this.name = ((Subject.Data) (arg)).name;
        this.sex = ((Subject.Data) (arg)).sex;
        System.out.println(name+"---2----"+sex);
    }
}

測試:

package com.example.springbootstarterhello.observe;

public class TestObserver {



    public static void main(String[] args) {
        Subject subject = new Subject();
        Observer1 observer1 = new Observer1();
        Observer2 observer2 = new Observer2();
        subject.addObserver(observer1);
        subject.addObserver(observer2);
        subject.setData("lroy","22");
        subject.deleteObserver(observer1);
        subject.setData("Jrcy","23");
    }
}

 

 

結果:(注意輸出順序,先進的后出,后進的先出

lroy---2----22
lroy---1----22
Jrcy---2----23

 

  12.策略模式(Strategy)

 1)給策略對象(槍)定義一個公共接口

1 public interface Weapon { 2 public void gun(); 3 }

(2)定義具體的策略類(ConcreteStrategy),實現上面的接口

public class FirstGun implements Weapon { @Override public void gun() { System.out.println("使用AWM狙擊步槍。"); } }
public class SecondGun implements Weapon { @Override public void gun() { System.out.println("使用S12K霰彈槍。"); } }

(3)定義一個環境類(Contex),類中持有一個對公共接口的引用,以及相應的get、set方法、構造方法

public class Context { Weapon weapon; public Context(Weapon weapon) { //構造函數 super(); this.weapon = weapon; } public Weapon getWeapon() { //get方法 return weapon; } public void setWeapon(Weapon weapon) { //set方法 this.weapon = weapon; } public void gun() { weapon.gun(); } }

最后,客戶端自由調用策略(我在槍林彈雨的戰場上,切換武器,擊斃敵人)

public class StrategyClient { public static void main(String[] args) { //使用構造函數默認選擇一把AWM狙擊步槍(一個策略) Context context=new Context(new FirstGun()); context.gun(); //使用get、set方法切換到S12K霰彈槍(切換策略)
     System.out.println("------右前方30米發現敵人------"); contex.set(new SecondGun()); context.gun();
} }
 

輸出結果:

 

 

 

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM