1. 單例模式:確保某一個類只有一個實例,而且自行實例化并向整個系統提供這 個實例。
(1)懶漢式 public?class?Singleton?{??/*?持有私有靜態實例,防止被引用,此處賦值為null,目的是實現延遲加載? */?? ????private?static?Singleton?instance?=?null;??/*?私有構造方法,防止被實例化?*/?? ???private?Singleton()?{?? ?}??/*?1:懶漢式,靜態工程方法,創建實例?*/?? ????public?static?Singleton?getInstance()?{?? ????????if?(instance?==?null)?{?? ????????????instance?=?new?Singleton();?? ???????}?? ????return?instance;?? ??}??} (2)餓漢式 public?class?Singleton?{??/*?持有私有靜態實例,防止被引用?*/?? ???? private?static?Singleton?instance?=?new?Singleton();??/*?私有構造方法,防止被實例化?*/?? ???private?Singleton()?{?? }??/*?1:懶漢式,靜態工程方法,創建實例?*/?? ????public?static?Singleton?getInstance()?{?? ??????return?instance;?? ??}?? }
使用場景:
- 要求生成唯一序列號的環境;
- 在整個項目中需要一個共享訪問點或共享數據,例如一個Web頁面上的計數 器,可以不用把每次刷新都記錄到數據庫中,使用單例模式保持計數器的值,并 確保是線程安全的;
- 創建一個對象需要消耗的資源過多,如要訪問IO和數據庫等資源;
- 需要定義大量的靜態常量和靜態方法(如工具類)的環境,可以采用單例模式 (當然,也可以直接聲明為static的方式)。
2. 工廠模式:定義一個用于創建對象的接口,讓子類決定實例化哪一個類。工廠 方法使一個類的實例化延遲到其子類。
接口public interface Fruit {
public void print(); }
2個實現類
public class Apple implements Fruit{ @Override public void print() { System.out.println("我是一個蘋果"); }
}
public class Orange implements Fruit{ @Override public void print() { System.out.println("我是一個橘子"); }
} 工廠類public class FruitFactory { public Fruit produce(String type){ if(type.equals("apple")){ return new Apple(); }else if(type.equals("orange")){ return new Orange(); }else{ System.out.println("請輸入正確的類型!"); return null; } }
}
使用場景:jdbc連接數據庫,硬件訪問,降低對象的產生和銷毀
3. 抽象工廠模式:為創建一組相關或相互依賴的對象提供一個接口,而且無須指 定它們的具體類。
相對于工廠模式,我們可以新增產品類(只需要實現產品接口),只需要同時新 增一個工廠類,客戶端就可以輕松調用新產品的代碼。
interface food{}
class A implements food{}
class B implements food{}
interface produce{ food get();}
class FactoryForA implements produce{ @Override public food get() { return new A(); }
}
class FactoryForB implements produce{ @Override public food get() { return new B(); }
}
public class AbstractFactory { public void ClientCode(String name){ food x= new FactoryForA().get(); x = new FactoryForB().get(); }
}
使用場景:一個對象族(或是一組沒有任何關系的對象)都有相同的約束。 涉及不同操作系統的時候,都可以考慮使用抽象工廠模式
4.建造者模式:將一個復雜對象的構建與它的表示分離,使得同樣的構建過程可 以創建不同的表示。
public class Build { static class Student{ String name = null ; int number = -1 ; String sex = null ; public Student(Builder builder) { this.name=builder.name; this.number=builder.number; this.sex=builder.sex; } static class Builder{String name = null ; int number = -1 ; String sex = null ; public Builder setName(String name){ this.name=name; return this; } public Builder setNumber(int number){ this.number=number; return this; } public Builder setSex(String sex){ this.sex=sex; return this; } public Student build(){ return new Student(this); }}
}
public static void main(String[] args) {
Student A=new Student.Builder().setName("張 三").setNumber(1).build(); Student B=new Student.Builder().setSex("男").setName("李四").build(); System.out.println(A.name+" "+A.number+" "+A.sex); System.out.println(B.name+" "+B.number+" "+B.sex); }
}
使用場景:
- 相同的方法,不同的執行順序,產生不同的事件結果時,可以采用建造者模 式。
- 多個部件或零件,都可以裝配到一個對象中,但是產生的運行結果又不相同 時,則可以使用該模式。
- 產品類非常復雜,或者產品類中的調用順序不同產生了不同的效能,這個時候 使用建造者模式非常合適。
5. 原型模式:用原型實例指定創建對象的種類,并且通過拷貝這些原型創建新的 對象。
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(); }
}
原型模式實際上就是實現Cloneable接口,重寫clone()方法。
使用原型模式的優點:
1.性能優良
原型模式是在內存二進制流的拷貝,要比直接new一個對象性能好很多,特別是 要在一個循環體內產生大量的對象時,原型模式可以更好地體現其優點。
2.逃避構造函數的約束
這既是它的優點也是缺點,直接在內存中拷貝,構造函數是不會執行的(參見 13.4節)。
使用場景:
資源優化場景 類初始化需要消化非常多的資源,這個資源包括數據、硬件資源等。
性能和安全要求的場景 通過new產生一個對象需要非常繁瑣的數據準備或訪問權限,則可以使用原型模 式。
一個對象多個修改者的場景 一個對象需要提供給其他對象訪問,而且各個調用者可能都需要修改其值時,可 以考慮使用原型模式拷貝多個對象供調用者使用。
淺拷貝和深拷貝:
淺拷貝:Object類提供的方法clone只是拷貝本對象,其對象內部的數組、引用 對象等都不拷貝,還是指向原生對象的內部元素地址,這種拷貝就叫做淺拷貝, 其他的原始類型比如int、long、char、string(當做是原始類型)等都會被拷 貝。
注意: 使用原型模式時,引用的成員變量必須滿足兩個條件才不會被拷貝:一 是類的成員變量,而不是方法內變量;二是必須是一個可變的引用對象,而不是 一個原始類型或不可變對象。
深拷貝:對私有的類變量進行獨立的拷貝
如:this.arrayList = (ArrayList)this.arrayList.clone();
6. 適配器模式:將一個類的接口變換成客戶端所期待的另一種接口,從而使原本 因接口不匹配而無法在一起工作的兩個類能夠在一起工作。
主要可分為3種:
- 類適配:創建新類,繼承源類,并實現新接口,例如 class adapter extends oldClass implements newFunc{}
- 對象適配:創建新類持源類的實例,并實現新接口,例如 class adapter implements newFunc { private oldClass oldInstance ;}
- 接口適配:創建新的抽象類實現舊接口方法。例如 abstract class adapter implements oldClassFunc { void newFunc();}
使用場景:
你有動機修改一個已經投產中的接口時,適配器模式可能是適合你的模式。比 如系統擴展了,需要使用一個已有或新建立的類,但這個類又不符合系統的接 口,怎么辦?使用適配器模式,這也是我們例子中提到的。
7. 裝飾器模式:動態地給一個對象添加一些額外的職責。就增加功能來說,裝飾 器模式相比生成子類更為靈活 。
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. 代理模式:為其他對象提供一種代理以控制對這個對象的訪問。
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. 中介者模式:用一個中介對象封裝一系列的對象交互,中介者使各對象不需要 顯示地相互作用,從而使其耦合松散,而且可以獨立地改變它們之間的交互。
public abstract class Mediator { //定義同事類 protected ConcreteColleague1 c1; protected ConcreteColleague2 c2; //通過getter/setter方法把同事類注入進來 public ConcreteColleague1 getC1() { return c1; }public void setC1(ConcreteColleague1 c1) { this.c1 = c1; } public ConcreteColleague2 getC2() { return c2; } public void setC2(ConcreteColleague2 c2) { this.c2 = c2; } //中介者模式的業務邏輯 public abstract void doSomething1(); public abstract void doSomething2();
}
使用場景: 中介者模式適用于多個對象之間緊密耦合的情況,緊密耦合的標準是:在類圖中 出現了蜘蛛網狀結構,即每個類都與其他的類有直接的聯系。
10. 命令模式:將一個請求封裝成一個對象,從而讓你使用不同的請求把客戶端 參數化,對請求排隊或者記錄請求日志,可以提供命令的撤銷和恢復功能。
Receiver接受者角色:該角色就是干活的角色,命令傳遞到這里是應該被執行的
Command命令角色:需要執行的所有命令都在這里聲明
Invoker調用者角色:接收到命令,并執行命令
//通用Receiver類
public abstract class Receiver { public abstract void doSomething();
}
//具體Receiver類
public class ConcreteReciver1 extends Receiver{ //每個接收者都必須處理一定的業務邏輯 public void doSomething(){ }
}
public class ConcreteReciver2 extends Receiver{ //每個接收者都必須處理一定的業務邏輯 public void doSomething(){ }
}
//抽象Command類 public abstract class Command { public abstract void execute();
}
//具體的Command類
public class ConcreteCommand1 extends Command { //對哪個Receiver類進行命令處理 private Receiver receiver; //構造函數傳遞接收者 public ConcreteCommand1(Receiver _receiver){ this.receiver = _receiver; } //必須實現一個命令 public void execute() { //業務處理 this.receiver.doSomething(); }
}
public class ConcreteCommand2 extends Command { //哪個Receiver類進行命令處理 private Receiver receiver; //構造函數傳遞接收者public ConcreteCommand2(Receiver _receiver){ this.receiver = _receiver;
}
//必須實現一個命令 public void execute() { //業務處理 this.receiver.doSomething(); } } //調用者Invoker類 public class Invoker { private Command command;public void setCommand(Command _command){ this.command = _command; }
public void action() { this.command.execute(); }
} //場景類
public class Client { public static void main(String[] args){ Invoker invoker = new Invoker(); Receiver receiver = new ConcreteReceiver1();Command command = new ConcreteCommand1(receiver); invoker.setCommand(command); invoker.action(); }
}
使用場景: 認為是命令的地方就可以采用命令模式,例如,在GUI開發中,一個按鈕的點擊 是一個命令,可以采用命令模式;模擬DOS命令的時候,當然也要采用命令模
式;觸發-反饋機制的處理等。
11.責任鏈模式:使多個對象都有機會處理請求,從而避免了請求的發送者和接受者之間的耦合關系。將這些對象連成一條鏈,并沿著這條鏈傳遞該請求,直到有對象處理它為止。
public abstract class Handler {private Handler nextHandler;//每個處理者都必須對請求做出處理public final Response handleMessage(Request request){Response response = null; //判斷是否是自己的處理級別if(this.getHandlerLevel().equals(request.getRequestLevel())){response = this.echo(request);}else{ //不屬于自己的處理級別//判斷是否有下一個處理者if(this.nextHandler != null){response = this.nextHandler.handleMessage(request);}else{//沒有適當的處理者,業務自行處理}}return response;}//設置下一個處理者是誰public void setNext(Handler _handler){this.nextHandler = _handler;}//每個處理者都有一個處理級別protected abstract Level getHandlerLevel();//每個處理者都必須實現處理任務protected abstract Response echo(Request request);
}
12.策略模式:定義一組算法,將每個算法都封裝起來,并且使它們之間可以互換。
使用場景:
-
多個類只有在算法或行為上稍有不同的場景。
-
算法需要自由切換的場景。
-
需要屏蔽算法規則的場景。
13.迭代器模式:它提供一種方法訪問一個容器對象中各個元素,而又不需暴露該對象的內部細節。
迭代器模式已經被淘汰,java中已經把迭代器運用到各個聚集類(collection)中了,使用java自帶的迭代器就已經滿足我們的需求了。
14.組合模式:將對象組合成樹形結構以表示“部分-整體”的層次結構,使得用戶對單個對象和組合對象的使用具有一致性。
public class Composite extends Component {//構件容器private ArrayList componentArrayList = new ArrayList();//增加一個葉子構件或樹枝構件public void add(Component component){this.componentArrayList.add(component);}//刪除一個葉子構件或樹枝構件public void remove(Component component){
this.componentArrayList.remove(component);}//獲得分支下的所有葉子構件和樹枝構件public ArrayList getChildren(){return this.componentArrayList;}
}
使用場景:
-
維護和展示部分-整體關系的場景,如樹形菜單、文件和文件夾管理。
-
從一個整體中能夠獨立出部分模塊或功能的場景。
15.觀察者模式:定義對象間一種一對多的依賴關系,使得每當一個對象改變狀態,則所有依賴于它的對象都會得到通知并被自動更新。
public abstract class Subject {//定義一個觀察者數組private Vector obsVector = new Vector();//增加一個觀察者public void addObserver(Observer o){this.obsVector.add(o);}//刪除一個觀察者public void delObserver(Observer o){this.obsVector.remove(o);}//通知所有觀察者public void notifyObservers(){for(Observer o:this.obsVector){o.update();
}}
}
使用場景:
-
關聯行為場景。需要注意的是,關聯行為是可拆分的,而不是“組合”關系。
-
事件多級觸發場景。
-
跨系統的消息交換場景,如消息隊列的處理機制
16.門面模式:要求一個子系統的外部與其內部的通信必須通過一個統一的對象進行。門面模式提供一個高層次的接口,使得子系統更易于使用。
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();}
}
使用場景:
-
為一個復雜的模塊或子系統提供一個供外界訪問的接口
-
子系統相對獨立——外界對子系統的訪問只要黑箱操作即可
-
預防低水平人員帶來的風險擴散
17.備忘錄模式:在不破壞封裝性的前提下,捕獲一個對象的內部狀態,并在該對象之外保存這個狀態。這樣以后就可將該對象恢復到原先保存的狀態。
public class Originator {private String state;/**
* 工廠方法,返回一個新的備忘錄對象*/public Memento createMemento(){return new Memento(state);}/**
* 將發起人恢復到備忘錄對象所記載的狀態*/public void restoreMemento(Memento memento){this.state = memento.getState();}public String getState() {return state;}public void setState(String state) {this.state = state;System.out.println("當前狀態:" + this.state);}
}
使用場景:
-
需要保存和恢復數據的相關狀態場景。
-
提供一個可回滾(rollback)的操作。
-
需要監控的副本場景中。
-
數據庫連接的事務管理就是用的備忘錄模式。
18.訪問者模式:封裝一些作用于某種數據結構中的各元素的操作,它可以在不改變數據結構的前提下定義作用于這些元素的新的操作。
使用場景:
-
一個對象結構包含很多類對象,它們有不同的接口,而你想對這些對象實施一些依賴于其具體類的操作,也就說是用迭代器模式已經不能勝任的情景。
-
需要對一個對象結構中的對象進行很多不同并且不相關的操作,而你想避免讓這些操作“污染”這些對象的類。
19.狀態模式:當一個對象內在狀態改變時允許其改變行為,這個對象看起來像改變了其類。
使用場景:
-
行為隨狀態改變而改變的場景這也是狀態模式的根本出發點,例如權限設計,人員的狀態不同即使執行相同的行為結果也會不同,在這種情況下需要考慮使用狀態模式。
-
條件、分支判斷語句的替代者
20.解釋器模式:給定一門語言,定義它的文法的一種表示,并定義一個解釋器,該解釋器使用該表示來解釋語言中的句子。
使用場景:
-
重復發生的問題可以使用解釋器模式
-
一個簡單語法需要解釋的場景
21.享元模式:使用共享對象的方法,用來盡可能減少內存使用量以及分享資訊。
abstract class flywei{ }
public class Flyweight extends flywei{Object obj ;public Flyweight(Object obj){this.obj = obj;}
}
class FlyweightFactory{ private HashMap 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;}}
}
使用場景:
-
系統中存在大量的相似對象。
-
細粒度的對象都具備較接近的外部狀態,而且內部狀態與環境無關,也就是說對象沒有特定身份。
-
需要緩沖池的場景。
22.橋梁模式:將抽象和實現解耦,使得兩者可以獨立地變化。
Circle類將DrwaApi與Shape類進行了橋接,
interface DrawAPI {public void drawCircle(int radius, int x, int y);
}
class RedCircle implements DrawAPI {@Overridepublic void drawCircle(int radius, int x, int y) {System.out.println("Drawing Circle[ color: red, radius: "+ radius +", x: " +x+", "+ y +"]");}
}
class GreenCircle implements DrawAPI {@Overridepublic 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();
使用場景:
-
不希望或不適用使用繼承的場景
-
接口或抽象類不穩定的場景
-
重用性要求較高的場景
23.模板方法模式:定義一個操作中的算法的框架,而將一些步驟延遲到子類中。使得子類可以不改變一個算法的結構即可重定義該算法的某些特定步驟。
使用場景:
-
多個子類有公有的方法,并且邏輯基本相同時。
-
重要、復雜的算法,可以把核心算法設計為模板方法,周邊的相關細節功能則由各個子類實現。
-
重構時,模板方法模式是一個經常使用的模式,把相同的代碼抽取到父類中,然后通過鉤子函數(見“模板方法模式的擴展”)約束其行為。