Java常用的設計模式總結

前言

java設計模式有23種,他們分別是:
創建型模式:單例模式、抽象工廠模式、建造者模式、工廠模式、原型模式。
結構型模式:適配器模式、橋接模式、裝飾器模式、組合模式、外觀模式、享元模式、代理模式。
行爲型模式:模版方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、解釋器模式、狀態模式、策略模式、職責鏈模式(責任鏈模式)、訪問者模式。
在這裏我們只介紹6種常用的設計模式:

1.單例模式

這種模式涉及到一個單一的類,該類負責創建自己的對象,同時確保只有單個對象被創建。這個類提供了一種訪問其唯一的對象的方式,可以直接訪問,不需要實例化該類的對象。

注意:

1、單例類只能有一個實例。
2、單例類必須自己創建自己的唯一實例。
3、單例類必須給所有其他對象提供這一實例。
單例模式有好多種,什麼餓漢模式和懶漢模式,下面介紹的這種方式採用雙鎖機制,安全且在多線程情況下能保持高性能。

public class Singleton {  
    private volatile static Singleton singleton;  
    private Singleton (){}  
    public static Singleton getSingleton() {  
    if (singleton == null) {  
        synchronized (Singleton.class) {  
        if (singleton == null) {  
            singleton = new Singleton();  
        }  
        }  
    }  
    return singleton;  
    }  
}

2.工廠模式

工廠模式(Factory Pattern)是 Java 中最常用的設計模式之一。這種類型的設計模式屬於創建型模式,它提供了一種創建對象的最佳方式。

在工廠模式中,我們在創建對象時不會對客戶端暴露創建邏輯,並且是通過使用一個共同的接口來指向新創建的對象。

實現步驟如下:

①、創建一個接口

public interface Shape {
   void draw();
}

②、創建實現接口的實現類

public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}

③、創建一個工廠,生成基於給定信息的實體類的對象。

public class ShapeFactory {
    
   //使用 getShape 方法獲取形狀類型的對象
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      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;
   }
}

④、使用該工廠,通過傳遞類型信息來獲取實體類的對象。

public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //獲取 Circle 的對象,並調用它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //調用 Circle 的 draw 方法
      shape1.draw();
 
      //獲取 Rectangle 的對象,並調用它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //調用 Rectangle 的 draw 方法
      shape2.draw();
 
      //獲取 Square 的對象,並調用它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //調用 Square 的 draw 方法
      shape3.draw();
   }
}

⑤、執行程序,輸出結果:

Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

3.適配器模式

適配器模式(Adapter Pattern)是作爲兩個不兼容的接口之間的橋樑。這種類型的設計模式屬於結構型模式,它結合了兩個獨立接口的功能。

這種模式涉及到一個單一的類,該類負責加入獨立的或不兼容的接口功能。舉個真實的例子,讀卡器是作爲內存卡和筆記本之間的適配器。您將內存卡插入讀卡器,再將讀卡器插入筆記本,這樣就可以通過筆記本來讀取內存卡。

我們通過下面的實例來演示適配器模式的使用。其中,音頻播放器設備只能播放 mp3 文件,通過使用一個更高級的音頻播放器來播放 vlc 和 mp4 文件。

步驟如下:

①、爲媒體播放器和更高級的媒體播放器創建接口。

public interface MediaPlayer {
   public void play(String audioType, String fileName);
}
public interface AdvancedMediaPlayer { 
   public void playVlc(String fileName);
   public void playMp4(String fileName);
}

②、創建實現了 AdvancedMediaPlayer 接口的實體類。

public class VlcPlayer implements AdvancedMediaPlayer{
   @Override
   public void playVlc(String fileName) {
      System.out.println("Playing vlc file. Name: "+ fileName);      
   }
 
   @Override
   public void playMp4(String fileName) {
      //什麼也不做
   }
}
public class Mp4Player implements AdvancedMediaPlayer{
 
   @Override
   public void playVlc(String fileName) {
      //什麼也不做
   }
 
   @Override
   public void playMp4(String fileName) {
      System.out.println("Playing mp4 file. Name: "+ fileName);      
   }
}

③、創建實現了 MediaPlayer 接口的適配器類。

public class MediaAdapter implements MediaPlayer {
 
   AdvancedMediaPlayer advancedMusicPlayer;
 
   public MediaAdapter(String audioType){
      if(audioType.equalsIgnoreCase("vlc") ){
         advancedMusicPlayer = new VlcPlayer();       
      } else if (audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer = new Mp4Player();
      }  
   }
 
   @Override
   public void play(String audioType, String fileName) {
      if(audioType.equalsIgnoreCase("vlc")){
         advancedMusicPlayer.playVlc(fileName);
      }else if(audioType.equalsIgnoreCase("mp4")){
         advancedMusicPlayer.playMp4(fileName);
      }
   }
}

④、創建實現了 MediaPlayer 接口的實體類。

public class AudioPlayer implements MediaPlayer {
   MediaAdapter mediaAdapter; 
 
   @Override
   public void play(String audioType, String fileName) {    
 
      //播放 mp3 音樂文件的內置支持
      if(audioType.equalsIgnoreCase("mp3")){
         System.out.println("Playing mp3 file. Name: "+ fileName);         
      } 
      //mediaAdapter 提供了播放其他文件格式的支持
      else if(audioType.equalsIgnoreCase("vlc") 
         || audioType.equalsIgnoreCase("mp4")){
         mediaAdapter = new MediaAdapter(audioType);
         mediaAdapter.play(audioType, fileName);
      }
      else{
         System.out.println("Invalid media. "+
            audioType + " format not supported");
      }
   }   
}

⑤、使用 AudioPlayer 來播放不同類型的音頻格式。

public class AdapterPatternDemo {
   public static void main(String[] args) {
      AudioPlayer audioPlayer = new AudioPlayer();
 
      audioPlayer.play("mp3", "beyond the horizon.mp3");
      audioPlayer.play("mp4", "alone.mp4");
      audioPlayer.play("vlc", "far far away.vlc");
      audioPlayer.play("avi", "mind me.avi");
   }
}

⑥、執行程序,輸出結果:

Playing mp3 file. Name: beyond the horizon.mp3
Playing mp4 file. Name: alone.mp4
Playing vlc file. Name: far far away.vlc
Invalid media. avi format not supported

4.裝飾器模式

裝飾器模式(Decorator Pattern)允許向一個現有的對象添加新的功能,同時又不改變其結構。這種類型的設計模式屬於結構型模式,它是作爲現有的類的一個包裝。

這種模式創建了一個裝飾類,用來包裝原有的類,並在保持類方法簽名完整性的前提下,提供了額外的功能。

裝飾模式爲已有類動態附加額外的功能就像LOL、王者榮耀等類Dota遊戲中,英雄升級一樣。每次英雄升級都會附加一個額外技能點學習技能。具體的英雄就是ConcreteComponent,技能欄就是裝飾器Decorator,每個技能就是ConcreteDecorator;

//Component 英雄接口 
public interface Hero {
    //學習技能
    void learnSkills();
}
//ConcreteComponent 具體英雄盲僧
public class BlindMonk implements Hero {
    
    private String name;
    
    public BlindMonk(String name) {
        this.name = name;
    }
 
    @Override
    public void learnSkills() {
        System.out.println(name + "學習了以上技能!");
    }
}
//Decorator 技能欄
public class Skills implements Hero{
    
    //持有一個英雄對象接口
    private Hero hero;
    
    public Skills(Hero hero) {
        this.hero = hero;
    }
 
    @Override
    public void learnSkills() {
        if(hero != null)
            hero.learnSkills();
    }    
}
//ConreteDecorator 技能:Q
public class Skill_Q extends Skills{
    
    private String skillName;
 
    public Skill_Q(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }
 
    @Override
    public void learnSkills() {
        System.out.println("學習了技能Q:" +skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:W
public class Skill_W extends Skills{
 
    private String skillName;
 
    public Skill_W(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }
 
    @Override
    public void learnSkills() {
        System.out.println("學習了技能W:" + skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:E
public class Skill_E extends Skills{
    
    private String skillName;
    
    public Skill_E(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }
 
    @Override
    public void learnSkills() {
        System.out.println("學習了技能E:"+skillName);
        super.learnSkills();
    }
}
//ConreteDecorator 技能:R
public class Skill_R extends Skills{    
    
    private String skillName;
    
    public Skill_R(Hero hero,String skillName) {
        super(hero);
        this.skillName = skillName;
    }
    
    @Override
    public void learnSkills() {
        System.out.println("學習了技能R:" +skillName );
        super.learnSkills();
    }
}
//客戶端:召喚師
public class Player {
    public static void main(String[] args) {
        //選擇英雄
        Hero hero = new BlindMonk("李青");
        
        Skills skills = new Skills(hero);
        Skills r = new Skill_R(skills,"猛龍擺尾");
        Skills e = new Skill_E(r,"天雷破/摧筋斷骨");
        Skills w = new Skill_W(e,"金鐘罩/鐵布衫");
        Skills q = new Skill_Q(w,"天音波/迴音擊");
        //學習技能
        q.learnSkills();
    }
}

輸出:

學習了技能Q:天音波/迴音擊
學習了技能W:金鐘罩/鐵布衫
學習了技能E:天雷破/摧筋斷骨
學習了技能R:猛龍擺尾
李青學習了以上技能!

5.外觀模式

外觀模式(Facade Pattern)隱藏系統的複雜性,並向客戶端提供了一個客戶端可以訪問系統的接口。這種類型的設計模式屬於結構型模式,它向現有的系統添加一個接口,來隱藏系統的複雜性。

這種模式涉及到一個單一的類,該類提供了客戶端請求的簡化方法和對現有系統類方法的委託調用。

我們將創建一個 Shape 接口和實現了 Shape 接口的實體類。下一步是定義一個外觀類 ShapeMaker。

ShapeMaker 類使用實體類來代表用戶對這些類的調用。FacadePatternDemo,我們的演示類使用 ShapeMaker 類來顯示結果。

①、創建一個接口。

public interface Shape {
   void draw();
}

②、創建實現接口的實體類。

public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Rectangle::draw()");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Square::draw()");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Circle::draw()");
   }
}

③、創建一個外觀類。

public class ShapeMaker {
   private Shape circle;
   private Shape rectangle;
   private Shape square;
 
   public ShapeMaker() {
      circle = new Circle();
      rectangle = new Rectangle();
      square = new Square();
   }
 
   public void drawCircle(){
      circle.draw();
   }
   public void drawRectangle(){
      rectangle.draw();
   }
   public void drawSquare(){
      square.draw();
   }
}

④、使用該外觀類畫出各種類型的形狀。

public class FacadePatternDemo {
   public static void main(String[] args) {
      ShapeMaker shapeMaker = new ShapeMaker();
 
      shapeMaker.drawCircle();
      shapeMaker.drawRectangle();
      shapeMaker.drawSquare();      
   }
}

⑤、執行程序,輸出結果:

Circle::draw()
Rectangle::draw()
Square::draw()

6.觀察者模式
當對象間存在一對多關係時,則使用觀察者模式(Observer Pattern)。比如,當一個對象被修改時,則會自動通知它的依賴對象。觀察者模式屬於行爲型模式。

觀察者模式,我理解的就是觀察者訂閱被觀察者的狀態,當被觀察者狀態改變的時候會通知所有訂閱的觀察者的過程。所以以下這種寫法會讓大家更加容易理解一些。

觀察者接口:

public abstract class Observer {    
    public abstract void update(String msg);
}

第一個觀察者:

public class F_Observer extends Observer {
    public void update(String msg) {
        System.out.println(F_Observer.class.getName() + " : " + msg);
    }
}

第二個觀察者:

public class S_Observer extends Observer {
    public void update(String msg) {
        System.out.println(S_Observer.class.getName() + " : " + msg);
    }
}

第三個觀察者:

public class T_Observer extends Observer {
    public void update(String msg) {
        System.out.println(T_Observer.class.getName() + " : " + msg);
    }
}

被觀察者:

public class Subject {        
    private List<Observer> observers = new ArrayList<>();    //狀態改變    
    public void setMsg(String msg) {        
        notifyAll(msg);    
    }   
     //訂閱    
    public void addAttach(Observer observer) {        
        observers.add(observer);    
    }    
    //通知所有訂閱的觀察者    
    private void notifyAll(String msg) {        
        for (Observer observer : observers) {            
            observer.update(msg);        
        }   
    }
}

使用方法:

public class Main {    
    public static void main(String[] args) {        
        F_Observer fObserver = new F_Observer();        
        S_Observer sObserver = new S_Observer();        
        T_Observer tObserver = new T_Observer();                
        Subject subject = new Subject();        
        subject.addAttach(fObserver);        
        subject.addAttach(sObserver);        
        subject.addAttach(tObserver);                
        subject.setMsg("msg change");    
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章