主要介紹
單例設計模式摧莽,代理設計模式,觀察者設計模式呵俏,模板模式(Template)堆缘, 適配器模式,裝飾模式(Decorator)普碎,命令模式(Command)吼肥,策略模式(Strategy);(單代命 觀模裝適)。
1. 單例模式:
一般包括:懶漢式單例麻车、餓漢式單例缀皱、登記式單例。
特點:
1动猬、單例類只能有一個實例啤斗。
2、單例類必須自己創(chuàng)建自己的唯一實例赁咙。用途:
在計算機系統(tǒng)中钮莲,線程池、緩存彼水、日志對象崔拥、對話框、打印機凤覆、顯卡的驅動程序對象常被設計成單例链瓦。示例:
//懶漢式單例類.在第一次調用的時候實例化自己
public class Singleton {
private Singleton() {}
private static Singleton single=null;
//靜態(tài)工廠方法
public static Singleton getInstance() {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
return singleton;
}
}
//靜態(tài)內部類時,不需要用同步
public class Singleton {
private static class LazyHolder {
private static final Singleton INSTANCE = new Singleton();
}
private Singleton (){}
public static final Singleton getInstance() {
return LazyHolder.INSTANCE;
}
}
//餓漢式單例類.在類初始化時盯桦,已經(jīng)自行實例化
public class Singleton1 {
private Singleton1() {}
private static final Singleton1 single = new Singleton1();
//靜態(tài)工廠方法
public static Singleton1 getInstance() {
return single;
}
}
//登記式單例
/*實際上維護了一組單例類的實例慈俯,將這些實例存放在一個Map(登記薄)中拥峦,對于已經(jīng)登記過的實例贴膘,則從Map直接返回,對于沒有登記的略号,則先登記步鉴,然后返回揪胃。它用的比較少且麻煩,另外其實內部實現(xiàn)還是用的餓漢式單例氛琢,這里忽略喊递。*/
2. 代理模式
是指客戶端并不直接調用實際的對象,而是通過調用代理阳似,來間接的調用實際的對象骚勘。
3. 命令模式
是指為了實現(xiàn)調用者角色與接收者角色之間,沒有任何依賴關系撮奏,即完全解耦俏讹。
命令模式的4個角色:
Command:定義命令的統(tǒng)一接口
ConcreteCommand:Command接口的實現(xiàn)者,用來執(zhí)行具體的命令畜吊,有時也直接用來充當Receiver泽疆。
Receiver:命令的實際執(zhí)行者
Invoker:命令的請求者,是命令模式中最重要的角色玲献。這個角色用來對各個命令進行控制殉疼。示例:
//通用Receiver類
public abstract class Receiver {
public abstract void doSomething();
}
//具體Receiver類
public class ConcreteReciver1 extends Receiver{
//每個接收者都必須處理一定的業(yè)務邏輯
public void doSomething(){ }
}
public class ConcreteReciver2 extends Receiver{
//每個接收者都必須處理一定的業(yè)務邏輯
public void doSomething(){ }
}
//抽象Command類
public abstract class Command {
public abstract void execute();
}
//具體的Command類
public class ConcreteCommand1 extends Command {
//對哪個Receiver類進行命令處理
private Receiver receiver;
//構造函數(shù)傳遞接收者
public ConcreteCommand1(Receiver _receiver){
this.receiver = _receiver;
}
//必須實現(xiàn)一個命令
public void execute() {
//業(yè)務處理
this.receiver.doSomething();
}
}
public class ConcreteCommand2 extends Command {
//哪個Receiver類進行命令處理
private Receiver receiver;
//構造函數(shù)傳遞接收者
public ConcreteCommand2(Receiver _receiver){
this.receiver = _receiver;
}
//必須實現(xiàn)一個命令
public void execute() {
//業(yè)務處理
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();
}
}
4. 觀察者設計模式
是指在對象之間定義了一對多的依賴,這樣一來捌年,當一個對象改變狀態(tài)瓢娜,依賴它的對象會收到通知并自動更新。
-
其包含四個角色:
- 抽象被觀察者角色:也就是一個抽象主題礼预,它把所有對觀察者對象的引用保存在一個集合中眠砾,每個主題都可以有任意數(shù)量的觀察者。抽象主題提供一個接口托酸,可以增加和刪除觀察者角色褒颈。一般用一個抽象類和接口來實現(xiàn)。
- 抽象觀察者角色:為所有的具體觀察者定義一個接口励堡,在得到主題通知時更新自己哈肖。
- 具體被觀察者角色:也就是一個具體的主題,在集體主題的內部狀態(tài)改變時念秧,所有登記過的觀察者發(fā)出通知。
- 具體觀察者角色:實現(xiàn)抽象觀察者角色所需要的更新接口布疼,一邊使本身的狀態(tài)與制圖的狀態(tài)相協(xié)調
使用場景舉例:
有一個微信公眾號服務摊趾,不定時發(fā)布一些消息,關注公眾號就可以收到推送消息游两,取消關注就收不到推送消息砾层。示例:
/***
* 抽象被觀察者接口
* 聲明了添加、刪除贱案、通知觀察者方法
* @author jstao
*
*/
public interface Observerable {
public void registerObserver(Observer o);
public void removeObserver(Observer o);
public void notifyObserver();
}
//定義一個抽象觀察者接口
/***
* 抽象觀察者
* 定義了一個update()方法肛炮,當被觀察者調用notifyObservers()方法時,觀察者的update()方法會被回調。
* @author jstao
*
*/
public interface Observer {
public void update(String message);
}
//定義被觀察者侨糟,實現(xiàn)了Observerable接口碍扔,對Observerable接口的三個方法進行了具體實現(xiàn),同時有一個List集合秕重,用以保存注冊的觀察者不同,等需要通知觀察者時,遍歷該集合即可溶耘。
/**
* 被觀察者二拐,也就是微信公眾號服務
* 實現(xiàn)了Observerable接口,對Observerable接口的三個方法進行了具體實現(xiàn)
* @author jstao
*
*/
public class WechatServer implements Observerable {
//注意到這個List集合的泛型參數(shù)為Observer接口凳兵,設計原則:面向接口編程而不是面向實現(xiàn)編程
private List<Observer> list;
private String message;
public WechatServer() {
list = new ArrayList<Observer>();
}
@Override
public void registerObserver(Observer o) {
list.add(o);
}
@Override
public void removeObserver(Observer o) {
if(!list.isEmpty())
list.remove(o);
}
//遍歷
@Override
public void notifyObserver() {
for(int i = 0; i < list.size(); i++) {
Observer oserver = list.get(i);
oserver.update(message);
}
}
public void setInfomation(String s) {
this.message = s;
System.out.println("微信服務更新消息: " + s);
//消息更新百新,通知所有觀察者
notifyObserver();
}
}
//定義具體觀察者,微信公眾號的具體觀察者為用戶User
/**
* 觀察者
* 實現(xiàn)了update方法
* @author jstao
*
*/
public class User implements Observer {
private String name;
private String message;
public User(String name) {
this.name = name;
}
@Override
public void update(String message) {
this.message = message;
read();
}
public void read() {
System.out.println(name + " 收到推送消息: " + message);
}
}
5. 模板模式
定義一個操作中算法的骨架庐扫,而將一些步驟延遲到子類中饭望。也就是說,要在父類中定義一個完成該事情的總方法聚蝶,按照完成事件需要的步驟去調用其每個步驟的實現(xiàn)方法杰妓。每個步驟的具體實現(xiàn),由子類完成碘勉。
- 示例:
public abstract class DodishTemplate { //模板類
/**
* 具體的整個過程
*/
protected void dodish(){
this.preparation();
this.doing();
this.carriedDishes();
}
/**
* 備料
*/
public abstract void preparation();
/**
* 做菜
*/
public abstract void doing();
/**
* 上菜
*/
public abstract void carriedDishes ();
}
public class EggsWithTomato extends DodishTemplate{ //具體實現(xiàn)類
@Override
public void preparation() {
System.out.println("洗并切西紅柿巷挥,打雞蛋。");
}
@Override
public void doing() {
System.out.println("雞蛋倒入鍋里验靡,然后倒入西紅柿一起炒倍宾。");
}
@Override
public void carriedDishes() {
System.out.println("將炒好的西紅寺雞蛋裝入碟子里,端給客人吃胜嗓。");
}
}
//代碼中調用:
DodishTemplate eggsWithTomato = new EggsWithTomato();
eggsWithTomato.dodish();
6. 裝飾模式
也叫做包裝模式高职,是結構型設計模式之一。目的是為了給一個類或對象增加行為辞州≌浚可以是繼承的一種替代。
四個角色:
Component:抽象組件变过,可以是一個接口或抽象類埃元,是被裝飾的原始對象
ConcreteComponent:組件的具體實現(xiàn)類。是被裝飾的具體對象媚狰。
Decorator:抽象的裝飾者岛杀。職責是裝飾被裝飾的對象。內部一定有一個對被裝飾者的引用崭孤。一般情況下也是一個抽象類类嗤,根據(jù)具體邏輯實現(xiàn)不同的子類糊肠。如果邏輯簡單可以直接是實現(xiàn)類。
ConcreteDecoratorA遗锣,B:具體的裝飾者货裹。示例:
//先抽象組件類:
public abstract class Component {
public abstract void operate();
}
組件的一個具體實現(xiàn)類,也就是被裝飾者者:
public class ConcreteComponent extends Component {
@Override
public void operate() {
System.out.println("被裝飾者的操作");
}
}
//抽象的裝飾者黄伊,持有一個被裝飾者的引用:
public abstract class Decorator extends Component {
private Component component;
public Decorator(Component component) { //采用傳參方式泪酱,替代繼承類的方式,這樣區(qū)分開繼承利于后期管理
this.component = component;
}
@Override
public void operate() {
component.operate();
}
}
//具體的兩個裝飾者还最,拓展功能:
public class ConcreteDecoratorA extends Decorator {
public ConcreteDecoratorA(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("裝飾者A在被裝飾者的操作之前加些操作");
}
private void operateB(){
System.out.println("裝飾者A在被裝飾者的操作之前后加些操作");
}
}
public class ConcreteDecoratorB extends Decorator {
public ConcreteDecoratorB(Component component) {
super(component);
}
@Override
public void operate() {
operateA();
super.operate();
operateB();
}
private void operateA(){
System.out.println("裝飾者B在被裝飾者的操作之前加些操作");
}
private void operateB(){
System.out.println("裝飾者B在被裝飾者的操作之前后加些操作");
}
}
//客戶端調用:
public class Client {
public static void main(String[] args) {
Component component = new ConcreteComponent();
ConcreteDecoratorA concreteDecoratorA = new ConcreteDecoratorA(component);
ConcreteDecoratorB concreteDecoratorB = new ConcreteDecoratorB(component);
concreteDecoratorA.operate();
concreteDecoratorB.operate();
}
}
7. 適配器模式
將一個類的接口轉換成客戶希望的另外一個接口墓阀。適配器模式使得原本由于接口不兼容而不能一起工作的那些類可以一起工作,可以理解成轉換器拓轻。 例子:https://blog.csdn.net/lmb55/article/details/51008762
8. 策略模式
定義了一系列的算法斯撮,并將每一個算法封裝起來,而且使他們可以相互替換扶叉,讓算法"獨立"于使用它的客戶而獨立變化勿锅。
使用場景:
1.針對同一類型問題的多種處理方式,僅僅是具體行為有差別時枣氧;
2.需要安全地封裝多種同一類型的操作時溢十;
3.出現(xiàn)同一抽象類有多個子類,而又需要使用 if-else 或者 switch-case 來選擇具體子類時达吞。示例:
public interface CalPrice {
//根據(jù)原價返回一個最終的價格
Double calPrice(Double orgnicPrice);
}
public class Orgnic implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice;
}
}
public class Vip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.9;
}
}
public class SuperVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.8;
}
}
public class GoldVip implements CalPrice {
@Override
public Double calPrice(Double orgnicPrice) {
return orgnicPrice * 0.7;
}
}
public class Player {
private Double totalAmount = 0D;//客戶在鵝廠消費的總額
private Double amount = 0D;//客戶單次消費金額
private CalPrice calPrice = new Orgnic();//每個客戶都有一個計算價格的策略张弛,初始都是普通計算,即原價
//客戶購買皮膚酪劫,就會增加它的總額
public void buy(Double amount) {
this.amount = amount;
totalAmount += amount;
if (totalAmount > 30000) {//30000則改為金牌會員計算方式
calPrice = new GoldVip();
} else if (totalAmount > 20000) {//類似
calPrice = new SuperVip();
} else if (totalAmount > 10000) {//類似
calPrice = new Vip();
}
}
//計算客戶最終要付的錢
public Double calLastAmount() {
return calPrice.calPrice(amount);
}
}
//調用
Player player = new Player();
player.buy(5000D);
System.out.println("玩家需要付錢:" + player.calLastAmount());