使多個對象都有機會處理請求,從而避免請求的發送者和接收者之間的耦合關係。 將這些對象連成一條鏈,並沿着這條鏈發送該請求,直到有一個對象處理它爲止。html
public abstract class Handler {
protected Handler successor;
public Handler(Handler successor) {
this.successor = successor;
}
protected abstract void handleRequest(Request request);
}
public class ConcreteHandler1 extends Handler {
public ConcreteHandler1(Handler successor) {
super(successor);
}
@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE1) {
System.out.println(request.getName() + " is handle by ConcreteHandler1");
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}
public class ConcreteHandler2 extends Handler {
public ConcreteHandler2(Handler successor) {
super(successor);
}
@Override
protected void handleRequest(Request request) {
if (request.getType() == RequestType.TYPE2) {
System.out.println(request.getName() + " is handle by ConcreteHandler2");
return;
}
if (successor != null) {
successor.handleRequest(request);
}
}
}
public class Request {
private RequestType type;
private String name;
public Request(RequestType type, String name) {
this.type = type;
this.name = name;
}
public RequestType getType() {
return type;
}
public String getName() {
return name;
}
}
public enum RequestType {
TYPE1, TYPE2
}
public class Client {
public static void main(String[] args) {
Handler h1=new ConcreteHandler1(null); //h1是沒有後繼的
Handler h2=new ConcreteHandler2(h1);//h2的後繼是h1
Request r1=new Request(RequestType.TYPE1,"request-1");
Request r2=new Request(RequestType.TYPE2,"request-2");
//使多個對象都有機會處理請求,從而
//TODO:避免請求的發送者和接受者之間的耦合關係。
//將這些對象連成一條鏈,並沿着這條鏈發送請求,一直到有一個對象處理它爲止。
//h2-->h1,這裏使用h2處理r1,最終交給h1處理
h2.handleRequest(r1);
//h2-->h1,這裏h2直接處理
h2.handleRequest(r2);
}
}
request-1 is handle by ConcreteHandler1
request-2 is handle by ConcreteHandler2複製代碼
職責鏈模式會定義一個全部處理請求的對象都要繼承實現的抽象類Handler,這樣就有利於隨時切換新的實現; 其次每一個處理請求對象只實現業務流程中的一步業務處理,這樣使其變得簡單; 最後職責鏈模式會動態的來組合這些處理請求的對象, 把它們按照流程動態組合起來,並要求它們依次調用,這樣就動態的實現了流程。java
將命令封裝成對象中,具備如下做用:git
/**
* 接收者,實際上是命令的真正執行者
*/
public class Receiver {
/**
* 真正執行命令操做
*/
public void action(){
//真正執行命令操做的功能代碼
System.out.println("真正執行命令操做的功能代碼");
}
}
public interface Command {
//執行命令的對應操做
public abstract void execute();
}
public class ConcreteCommand implements Command{
private Receiver receiver;
public ConcreteCommand(Receiver receiver){
this.receiver=receiver;
}
@Override
public void execute() {
receiver.action();
}
}
/**
* 命令的調用者
*/
public class Invoker {
private Command command;
public Invoker(Command command){
this.command=command;
}
//執行命令
public void executeCommand(){
command.execute();
}
}
public class Client {
public static void main(String[] args) {
//接收者,實際上是命令的真正執行者
Receiver receiver=new Receiver();
Command c=new ConcreteCommand(receiver);
//命令的調用者
Invoker invoker=new Invoker(c);
invoker.executeCommand();
}
}複製代碼
設計一個遙控器,能夠控制電燈開關。github
public interface Command {
void execute();
}
public class LightOnCommand implements Command {
Light light;
public LightOnCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.on();
}
}
public class LightOffCommand implements Command {
Light light;
public LightOffCommand(Light light) {
this.light = light;
}
@Override
public void execute() {
light.off();
}
}
public class Light {
public void on() {
System.out.println("Light is on!");
}
public void off() {
System.out.println("Light is off!");
}
}
/**
* 遙控器,也就是命令的調用者
*/
public class RemoteContol {
private Command[] onCommands;
private Command[] offCommands;
private final int slotNum = 7;
public RemoteContol(){
onCommands=new LightOnCommand[slotNum];
offCommands=new LightOffCommand[slotNum];
}
public void setOnCommand(Command command, int slot) {
onCommands[slot] = command;
}
public void setOffCommand(Command command, int slot) {
offCommands[slot] = command;
}
public void onButtonWasPushed(int slot) {
onCommands[slot].execute();
}
public void offButtonWasPushed(int slot) {
offCommands[slot].execute();
}
}
public class Client {
public static void main(String[] args) {
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
RemoteContol remoteContol=new RemoteContol();
remoteContol.setOnCommand(lightOnCommand, 0);
remoteContol.setOffCommand(lightOffCommand, 0);
//執行命令
remoteContol.onButtonWasPushed(0);
remoteContol.offButtonWasPushed(0);
}
}複製代碼
定義一個語法,定義一個解釋器,該解釋器處理該語法句子。算法
Implementationexpress
如下是一個規則檢驗器實現,具備 and 和 or 規則,經過規則能夠構建一顆解析樹,用來檢驗一個文本是否知足解析樹定義的規則。apache
例如一顆解析樹爲 D And (A Or (B C)),文本 "D A" 知足該解析樹定義的規則。api
這裏的 Context 指的是 String。bash
public abstract class Expression {
public abstract boolean interpret(String str);
}
public class TerminalExpression extends Expression {
private String literal = null;
public TerminalExpression(String str) {
literal = str;
}
public boolean interpret(String str) {
StringTokenizer st = new StringTokenizer(str);
while (st.hasMoreTokens()) {
String test = st.nextToken();
if (test.equals(literal)) {
return true;
}
}
return false;
}
}
public class AndExpression extends Expression {
private Expression expression1 = null;
private Expression expression2 = null;
public AndExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
public boolean interpret(String str) {
return expression1.interpret(str) && expression2.interpret(str);
}
}
public class OrExpression extends Expression {
private Expression expression1 = null;
private Expression expression2 = null;
public OrExpression(Expression expression1, Expression expression2) {
this.expression1 = expression1;
this.expression2 = expression2;
}
public boolean interpret(String str) {
return expression1.interpret(str) || expression2.interpret(str);
}
}
public class Client {
/**
* 構建解析樹
*/
public static Expression buildInterpreterTree() {
// Literal
Expression terminal1 = new TerminalExpression("A");
Expression terminal2 = new TerminalExpression("B");
Expression terminal3 = new TerminalExpression("C");
Expression terminal4 = new TerminalExpression("D");
// B C
Expression alternation1 = new OrExpression(terminal2, terminal3);
// A Or (B C)
Expression alternation2 = new OrExpression(terminal1, alternation1);
// D And (A Or (B C))
return new AndExpression(terminal4, alternation2);
}
public static void main(String[] args) {
Expression define = buildInterpreterTree();
String context1 = "D A";
String context2 = "A B";
System.out.println(define.interpret(context1));
System.out.println(define.interpret(context2));
}
}
true
false複製代碼
1.儘可能不要在重要的模塊中使用解釋器模式oracle
2.解釋器在實際系統開發中使用較少
3.能夠考慮使用開源的Expression4J、Jep等開源的解析工具包
提供一種順序訪問聚合對象元素的方法,而且不暴露聚合對象的內部表示。
public interface Aggregate {
Iterator createIterator();
}
public class ConcreteAggregate implements Aggregate {
private Integer[] items;
public ConcreteAggregate() {
items = new Integer[10];
for (int i = 0; i < items.length; i++) {
items[i] = i;
}
}
@Override
public Iterator createIterator() {
return new ConcreteIterator<Integer>(items);
}
}
public interface Iterator<Item> {
Item next();
boolean hasNext();
}
public class ConcreteIterator<Item> implements Iterator {
private Item[] items;
private int position = 0;
public ConcreteIterator(Item[] items) {
this.items = items;
}
@Override
public Object next() {
return items[position++];
}
@Override
public boolean hasNext() {
return position < items.length;
}
}
public class Client {
public static void main(String[] args) {
Aggregate aggregate = new ConcreteAggregate();
Iterator<Integer> iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}複製代碼
集中相關對象之間複雜的溝通和控制方式。
Implementation
Alarm(鬧鐘)、CoffeePot(咖啡壺)、Calendar(日曆)、Sprinkler(噴頭)是一組相關的對象,在某個對象的事件產生時須要去操做其它對象,造成了下面這種依賴結構:
使用中介者模式能夠將複雜的依賴結構變成星形結構:
public abstract class Colleague {
public abstract void onEvent(Mediator mediator);
}
public class Alarm extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("alarm");
}
public void doAlarm() {
System.out.println("doAlarm()");
}
}
public class CoffeePot extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("coffeePot");
}
public void doCoffeePot() {
System.out.println("doCoffeePot()");
}
}
public class Calendar extends Colleague{
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("calendar");
}
public void doCalendar(){
System.out.println("doCalendar()");
}
}
public class Sprinkler extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("sprinkler");
}
public void doSprinkler() {
System.out.println("doSprinkler()");
}
}
public abstract class Mediator {
public abstract void doEvent(String eventType);
}
public class ConcreteMediator extends Mediator{
private Alarm alarm;
private CoffeePot coffeePot;
private Calendar calendar;
private Sprinkler sprinkler;
public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calendar calendar, Sprinkler sprinkler) {
this.alarm = alarm;
this.coffeePot = coffeePot;
this.calendar = calendar;
this.sprinkler = sprinkler;
}
@Override
public void doEvent(String eventType) {
switch (eventType) {
case "alarm":
doAlarmEvent();
break;
case "coffeePot":
doCoffeePotEvent();
break;
case "calendar":
doCalenderEvent();
break;
default:
doSprinklerEvent();
}
}
public void doAlarmEvent() {
alarm.doAlarm();
coffeePot.doCoffeePot();
calendar.doCalendar();
sprinkler.doSprinkler();
}
public void doCoffeePotEvent() {
// ...
}
public void doCalenderEvent() {
// ...
}
public void doSprinklerEvent() {
// ...
}
}
public class Client {
public static void main(String[] args) {
Alarm alarm = new Alarm();
CoffeePot coffeePot = new CoffeePot();
Calendar calender = new Calendar();
Sprinkler sprinkler = new Sprinkler();
Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
// 鬧鐘事件到達,調用中介者就能夠操做相關對象
alarm.onEvent(mediator);
}
}
doAlarm()
doCoffeePot()
doCalendar()
doSprinkler()複製代碼
在不違反封裝的狀況下得到對象的內部狀態,從而在須要時能夠將對象恢復到最初狀態。
如下實現了一個簡單計算器程序,能夠輸入兩個值,而後計算這兩個值的和。 備忘錄模式容許將這兩個值存儲起來,而後在某個時刻用存儲的狀態進行恢復。
/**
* Originator Interface
*/
public interface Calculator {
// Create Memento
PreviousCalculationToCareTaker backupLastCalculation();
// setMemento
void restorePreviousCalculation(PreviousCalculationToCareTaker memento);
int getCalculationResult();
void setFirstNumber(int firstNumber);
void setSecondNumber(int secondNumber);
}
/**
* Originator Implementation
*/
public class CalculatorImp implements Calculator {
private int firstNumber;
private int secondNumber;
@Override
public PreviousCalculationToCareTaker backupLastCalculation() {
// create a memento object used for restoring two numbers
return new PreviousCalculationImp(firstNumber, secondNumber);
}
@Override
public void restorePreviousCalculation(PreviousCalculationToCareTaker memento) {
this.firstNumber = ((PreviousCalculationToOriginator) memento).getFirstNumber();
this.secondNumber = ((PreviousCalculationToOriginator) memento).getSecondNumber();
}
@Override
public int getCalculationResult() {
// result is adding two numbers
return firstNumber + secondNumber;
}
@Override
public void setFirstNumber(int firstNumber) {
this.firstNumber = firstNumber;
}
@Override
public void setSecondNumber(int secondNumber) {
this.secondNumber = secondNumber;
}
}
/**
* Memento Interface to Originator
*
* This interface allows the originator to restore its state
*/
public interface PreviousCalculationToOriginator {
int getFirstNumber();
int getSecondNumber();
}
/**
* Memento interface to CalculatorOperator (Caretaker)
*/
public interface PreviousCalculationToCareTaker {
// no operations permitted for the caretaker
}
/**
* Memento Object Implementation
* <p>
* Note that this object implements both interfaces to Originator and CareTaker
*/
public class PreviousCalculationImp implements PreviousCalculationToCareTaker,
PreviousCalculationToOriginator {
private int firstNumber;
private int secondNumber;
public PreviousCalculationImp(int firstNumber, int secondNumber) {
this.firstNumber = firstNumber;
this.secondNumber = secondNumber;
}
@Override
public int getFirstNumber() {
return firstNumber;
}
@Override
public int getSecondNumber() {
return secondNumber;
}
}
/**
* CareTaker object
*/
public class Client {
public static void main(String[] args) {
// program starts
Calculator calculator = new CalculatorImp();
// assume user enters two numbers
calculator.setFirstNumber(10);
calculator.setSecondNumber(100);
// find result
System.out.println(calculator.getCalculationResult());
// Store result of this calculation in case of error
PreviousCalculationToCareTaker memento = calculator.backupLastCalculation();
// user enters a number
calculator.setFirstNumber(17);
// user enters a wrong second number and calculates result
calculator.setSecondNumber(-290);
// calculate result
System.out.println(calculator.getCalculationResult());
// user hits CTRL + Z to undo last operation and see last result
calculator.restorePreviousCalculation(memento);
// result restored
System.out.println(calculator.getCalculationResult());
}
}
110
-273
110複製代碼
定義對象之間的一對多依賴,當一個對象狀態改變時,它的全部依賴都會收到通知而且自動更新狀態。
主題(Subject)是被觀察的對象,而其全部依賴者(Observer)稱爲觀察者。
Class Diagram
主題(Subject)具備註冊和移除觀察者、並通知全部觀察者的功能,主題是經過維護一張觀察者列表來實現這些操做的。
觀察者(Observer)的註冊功能須要調用主題的 registerObserver() 方法。
Implementation
天氣數據佈告板會在天氣信息發生改變時更新其內容,佈告板有多個,而且在未來會繼續增長。
public interface Subject {
void registerObserver(Observer o);
void removeObserver(Observer o);
void notifyObserver();
}
public class WeatherData implements Subject {
private List<Observer> observers;
private float temperature;
private float humidity;
private float pressure;
public WeatherData() {
observers = new ArrayList<>();
}
public void setMeasurements(float temperature, float humidity, float pressure) {
this.temperature = temperature;
this.humidity = humidity;
this.pressure = pressure;
notifyObserver();
}
@Override
public void registerObserver(Observer o) {
observers.add(o);
}
@Override
public void removeObserver(Observer o) {
int i = observers.indexOf(o);
if (i >= 0) {
observers.remove(i);
}
}
@Override
public void notifyObserver() {
for (Observer o : observers) {
o.update(temperature, humidity, pressure);
}
}
}
public interface Observer {
void update(float temp, float humidity, float pressure);
}
public class StatisticsDisplay implements Observer {
public StatisticsDisplay(Subject weatherData) {
weatherData.reisterObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
System.out.println("StatisticsDisplay.update: " + temp + " " + humidity + " " + pressure);
}
}
public class CurrentConditionsDisplay implements Observer {
public CurrentConditionsDisplay(Subject weatherData) {
weatherData.registerObserver(this);
}
@Override
public void update(float temp, float humidity, float pressure) {
System.out.println("CurrentConditionsDisplay.update: " + temp + " " + humidity + " " + pressure);
}
}
/**
* 天氣預報
*/
public class WeatherForecast {
public static void main(String[] args) {
WeatherData weatherData=new WeatherData();
Observer observer=new StatisticsDisplay(weatherData);
Observer observer2=new CurrentConditionsDisplay(weatherData);
weatherData.setMeasurements(0.0f,0.0f,0.0f);
weatherData.setMeasurements(1.0f,1.0f,1.0f);
}
}
CurrentConditionsDisplay.update: 0.0 0.0 0.0
StatisticsDisplay.update: 0.0 0.0 0.0
CurrentConditionsDisplay.update: 1.0 1.0 1.0
StatisticsDisplay.update: 1.0 1.0 1.0複製代碼
容許對象在內部狀態改變時改變它的行爲,對象看起來好像修改了它所屬的類。
Context:環境,也稱上下文,一般用來定義客戶感興趣的接口,同時維護一個來具體處理當前狀態的實例對象。
State:狀態接口,用來封裝與上下文的一個特定狀態所對應的行爲。
ConcreteState:具體實現狀態處理的類,每一個類實現一個跟上下文相關的狀態的具體處理。
實如今線投票:
一個在線投票的應用,要實現控制同一個用戶只能投一票,若是一個用戶反覆投票,並且投票次數超過5次, 則斷定爲惡意刷票,要取消該用戶投票的資格,固然同時也要取消他所投的票。 若是一個用戶的投票次數超過8次,將進入黑名單,禁止再登陸和使用系統。
在投票的過程當中,又有四種狀況:
程序結構以下圖:
/**
* 封裝一個投票狀態相關的行爲
*/
public interface VoteState {
/**
* TODO:處理狀態對應的行爲
* @param voter 投票人
* @param voteManager 投票上下文,用來在實現狀態對應的功能處理的時候,能夠回調上下文的數據
*/
void vote(String voter, VoteManager voteManager);
}
/**
* 投票管理器
*/
public class VoteManager {
//持有狀態處理對象
private VoteState state = null;
//統計用戶投票數
private Map<String,Integer> mapVoteCount = new HashMap<String,Integer>();
public Map<String,Integer> getMapVoteCount(){
return mapVoteCount;
}
/**
* 投票
* @param user 投票人,爲了簡單,就是用戶名稱
*/
public void vote(String user){
//1:先爲該用戶增長投票的次數
int voteCount=mapVoteCount.getOrDefault(user,0);
mapVoteCount.put(user, ++voteCount);
//2:判斷該用戶投票的類型,就至關因而判斷對應的狀態
//究竟是正常投票、重複投票、惡意投票仍是上黑名單的狀態
if(voteCount==1){
state = new NormalVoteState();
}else if(voteCount>1 && voteCount<5){
state = new RepeatVoteState();
}else if(voteCount >= 5 && voteCount<8){
state = new SpiteVoteState();
}else if(voteCount>=8){
state = new BlackVoteState();
}
//而後轉調狀態對象來進行相應的操做
state.vote(user, this);
}
}
/**
* 正常投票
*/
public class NormalVoteState implements VoteState{
@Override
public void vote(String voter, VoteManager voteManager) {
System.out.println("恭喜你投票成功");
}
}
/**
* 重複投票
*/
public class RepeatVoteState implements VoteState{
@Override
public void vote(String voter, VoteManager voteManager) {
System.out.println("請不要重複投票");
}
}
/**
* 惡意投票
*/
public class SpiteVoteState implements VoteState{
@Override
public void vote(String voter, VoteManager voteManager) {
System.out.println("你有惡意刷票行爲,取消投票資格");
}
}
/**
* 黑名單
* 記入黑名單中,禁止登陸系統了
*/
public class BlackVoteState implements VoteState{
@Override
public void vote(String voter, VoteManager voteManager) {
System.out.println("進入黑名單,將禁止登陸和使用本系統");
}
}
public class Client {
public static void main(String[] args) {
VoteManager vm = new VoteManager();
for (int i = 0; i < 9; i++) {
vm.vote("u1");
}
}
}複製代碼
輸出結果:
恭喜你投票成功
請不要重複投票
請不要重複投票
請不要重複投票
你有惡意刷票行爲,取消投票資格
你有惡意刷票行爲,取消投票資格
你有惡意刷票行爲,取消投票資格
進入黑名單,將禁止登陸和使用本系統
進入黑名單,將禁止登陸和使用本系統複製代碼
糖果銷售機有多種狀態,每種狀態下銷售機有不一樣的行爲,狀態能夠發生轉移,使得銷售機的行爲也發生改變。
public interface State {
/**
* 投入 25 分錢
*/
void insertQuarter();
/**
* 退回 25 分錢
*/
void ejectQuarter();
/**
* 轉動曲柄
*/
void turnCrank();
/**
* 發放糖果
*/
void dispense();
}
public class HasQuarterState implements State {
private GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You can't insert another quarter");
}
@Override
public void ejectQuarter() {
System.out.println("Quarter returned");
gumballMachine.setState(gumballMachine.getNoQuarterState());
}
@Override
public void turnCrank() {
System.out.println("You turned...");
gumballMachine.setState(gumballMachine.getSoldState());
}
@Override
public void dispense() {
System.out.println("No gumball dispensed");
}
}
public class NoQuarterState implements State {
GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You insert a quarter");
gumballMachine.setState(gumballMachine.getHasQuarterState());
}
@Override
public void ejectQuarter() {
System.out.println("You haven't insert a quarter");
}
@Override
public void turnCrank() {
System.out.println("You turned, but there's no quarter");
}
@Override
public void dispense() {
System.out.println("You need to pay first");
}
}
public class SoldOutState implements State {
GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("You can't insert a quarter, the machine is sold out");
}
@Override
public void ejectQuarter() {
System.out.println("You can't eject, you haven't inserted a quarter yet");
}
@Override
public void turnCrank() {
System.out.println("You turned, but there are no gumballs");
}
@Override
public void dispense() {
System.out.println("No gumball dispensed");
}
}
public class SoldState implements State {
GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("Please wait, we're already giving you a gumball");
}
@Override
public void ejectQuarter() {
System.out.println("Sorry, you already turned the crank");
}
@Override
public void turnCrank() {
System.out.println("Turning twice doesn't get you another gumball!");
}
@Override
public void dispense() {
gumballMachine.releaseBall();
if (gumballMachine.getCount() > 0) {
gumballMachine.setState(gumballMachine.getNoQuarterState());
} else {
System.out.println("Oops, out of gumballs");
gumballMachine.setState(gumballMachine.getSoldOutState());
}
}
}
public class GumballMachine {
private State soldOutState;
private State noQuarterState;
private State hasQuarterState;
private State soldState;
private State state;
private int count = 0;
public GumballMachine(int numberGumballs) {
count = numberGumballs;
soldOutState = new SoldOutState(this);
noQuarterState = new NoQuarterState(this);
hasQuarterState = new HasQuarterState(this);
soldState = new SoldState(this);
if (numberGumballs > 0) {
state = noQuarterState;
} else {
state = soldOutState;
}
}
public void insertQuarter() {
state.insertQuarter();
}
public void ejectQuarter() {
state.ejectQuarter();
}
public void turnCrank() {
state.turnCrank();
state.dispense();
}
public void setState(State state) {
this.state = state;
}
public void releaseBall() {
System.out.println("A gumball comes rolling out the slot...");
if (count != 0) {
count -= 1;
}
}
public State getSoldOutState() {
return soldOutState;
}
public State getNoQuarterState() {
return noQuarterState;
}
public State getHasQuarterState() {
return hasQuarterState;
}
public State getSoldState() {
return soldState;
}
public int getCount() {
return count;
}
}
public class Client {
public static void main(String[] args) {
GumballMachine gumballMachine = new GumballMachine(5);
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.ejectQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.ejectQuarter();
gumballMachine.insertQuarter();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
gumballMachine.insertQuarter();
gumballMachine.turnCrank();
}
}
You insert a quarter
You turned...
A gumball comes rolling out the slot...
You insert a quarter
Quarter returned
You turned, but there's no quarter You need to pay first You insert a quarter You turned... A gumball comes rolling out the slot... You insert a quarter You turned... A gumball comes rolling out the slot... You haven't insert a quarter
You insert a quarter
You can't insert another quarter You turned... A gumball comes rolling out the slot... You insert a quarter You turned... A gumball comes rolling out the slot... Oops, out of gumballs You can't insert a quarter, the machine is sold out
You turned, but there are no gumballs
No gumball dispensed複製代碼
定義一系列算法,封裝每一個算法,並使它們能夠互換。
策略模式可讓算法獨立於使用它的客戶端。
狀態模式的類圖和策略模式相似,而且都是可以動態改變對象的行爲。 可是狀態模式是經過狀態轉移來改變 Context 所組合的 State 對象, 而策略模式是經過 Context 自己的決策來改變組合的 Strategy 對象。 所謂的狀態轉移,是指 Context 在運行過程當中因爲一些條件發生改變而使得 State 對象發生改變, 注意必需要是在運行過程當中。
狀態模式主要是用來解決狀態轉移的問題,當狀態發生轉移了,那麼 Context 對象就會改變它的行爲; 而策略模式主要是用來封裝一組能夠互相替代的算法族,而且能夠根據須要動態地去替換 Context 使用的算法。
設計一個鴨子,它能夠動態地改變叫聲。這裏的算法族是鴨子的叫聲行爲。
public interface QuackBehavior {
void quack();
}
public class Quack implements QuackBehavior {
@Override
public void quack() {
System.out.println("quack!");
}
}
public class Squeak implements QuackBehavior{
@Override
public void quack() {
System.out.println("squeak!");
}
}
public class Duck {
private QuackBehavior quackBehavior;
public void performQuack() {
if (quackBehavior != null) {
quackBehavior.quack();
}
}
public void setQuackBehavior(QuackBehavior quackBehavior) {
this.quackBehavior = quackBehavior;
}
}
public class Client {
public static void main(String[] args) {
Duck duck = new Duck();
duck.setQuackBehavior(new Squeak());
duck.performQuack();
duck.setQuackBehavior(new Quack());
duck.performQuack();
}
}
squeak!
quack!複製代碼
報價管理:向客戶報價,對於銷售部門的人來說,這是一個很是重大、很是複雜的問題,對不一樣的客戶要報不一樣的價格,好比:
/**
* 策略,定義計算報價算法的接口
*/
public interface Strategy {
/**
* 計算報價
* @param goodsPrice 商品原價
* @return
*/
double calcPrice(double goodsPrice);
}
public class NormalCustomerStrategy implements Strategy{
@Override
public double calcPrice(double goodsPrice) {
System.out.println("對於新客戶或者是普通客戶,沒有折扣");
return goodsPrice;
}
}
public class OldCustomerStrategy implements Strategy{
@Override
public double calcPrice(double goodsPrice) {
System.out.println("對於老客戶,統一折扣5%");
return goodsPrice*(1-0.05);
}
}
public class LargeCustomerStrategy implements Strategy{
@Override
public double calcPrice(double goodsPrice) {
System.out.println("對於大客戶,統一折扣10%");
return goodsPrice*(1-0.1);
}
}
public class Price {
private Strategy strategy;
public double price(double goodsPrice){
return strategy.calcPrice(goodsPrice);
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
public class Client {
public static void main(String[] args) {
//1:選擇並建立須要使用的策略對象
Strategy strategy = new BigCustomerStrategy ();
//2:建立上下文
Price ctx = new Price();
ctx.setStrategy(strategy);
//3:計算報價
double price = ctx.price(1000);
System.out.println("向客戶報價:"+price);
}
}複製代碼
定義算法框架,並將一些步驟的實現延遲到子類。
經過模板方法,子類能夠從新定義算法的某些步驟,而不用改變算法的結構。
衝咖啡和沖茶都有相似的流程,可是某些步驟會有點不同,要求複用那些相同步驟的代碼。
public abstract class CaffeineBeverage {
final void prepareRecipe() {
boilWater();
brew();
pourInCup();
addCondiments();
}
abstract void brew();
abstract void addCondiments();
void boilWater() {
System.out.println("boilWater");
}
void pourInCup() {
System.out.println("pourInCup");
}
}
public class Coffee extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Coffee.brew");
}
@Override
void addCondiments() {
System.out.println("Coffee.addCondiments");
}
}
public class Tea extends CaffeineBeverage {
@Override
void brew() {
System.out.println("Tea.brew");
}
@Override
void addCondiments() {
System.out.println("Tea.addCondiments");
}
}
public class Client {
public static void main(String[] args) {
CaffeineBeverage caffeineBeverage = new Coffee();
caffeineBeverage.prepareRecipe();
System.out.println("-----------");
caffeineBeverage = new Tea();
caffeineBeverage.prepareRecipe();
}
}
boilWater
Coffee.brew
pourInCup
Coffee.addCondiments
-----------
boilWater
Tea.brew
pourInCup
Tea.addCondiments複製代碼
爲一個對象結構(好比組合結構)增長新能力。
Implementation
public interface Element {
void accept(Visitor visitor);
}
class CustomerGroup {
private List<Customer> customers = new ArrayList<>();
void accept(Visitor visitor) {
for (Customer customer : customers) {
customer.accept(visitor);
}
}
void addCustomer(Customer customer) {
customers.add(customer);
}
}
public class Customer implements Element {
private String name;
private List<Order> orders = new ArrayList<>();
Customer(String name) {
this.name = name;
}
String getName() {
return name;
}
void addOrder(Order order) {
orders.add(order);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Order order : orders) {
order.accept(visitor);
}
}
}
public class Order implements Element {
private String name;
private List<Item> items = new ArrayList();
Order(String name) {
this.name = name;
}
Order(String name, String itemName) {
this.name = name;
this.addItem(new Item(itemName));
}
String getName() {
return name;
}
void addItem(Item item) {
items.add(item);
}
public void accept(Visitor visitor) {
visitor.visit(this);
for (Item item : items) {
item.accept(visitor);
}
}
}
public class Item implements Element {
private String name;
Item(String name) {
this.name = name;
}
String getName() {
return name;
}
public void accept(Visitor visitor) {
visitor.visit(this);
}
}
public interface Visitor {
void visit(Customer customer);
void visit(Order order);
void visit(Item item);
}
public class GeneralReport implements Visitor {
private int customersNo;
private int ordersNo;
private int itemsNo;
public void visit(Customer customer) {
System.out.println(customer.getName());
customersNo++;
}
public void visit(Order order) {
System.out.println(order.getName());
ordersNo++;
}
public void visit(Item item) {
System.out.println(item.getName());
itemsNo++;
}
public void displayResults() {
System.out.println("Number of customers: " + customersNo);
System.out.println("Number of orders: " + ordersNo);
System.out.println("Number of items: " + itemsNo);
}
}
public class Client {
public static void main(String[] args) {
Customer customer1 = new Customer("customer1");
customer1.addOrder(new Order("order1", "item1"));
customer1.addOrder(new Order("order2", "item1"));
customer1.addOrder(new Order("order3", "item1"));
Order order = new Order("order_a");
order.addItem(new Item("item_a1"));
order.addItem(new Item("item_a2"));
order.addItem(new Item("item_a3"));
Customer customer2 = new Customer("customer2");
customer2.addOrder(order);
CustomerGroup customers = new CustomerGroup();
customers.addCustomer(customer1);
customers.addCustomer(customer2);
GeneralReport visitor = new GeneralReport();
customers.accept(visitor);
visitor.displayResults();
}
}
customer1
order1
item1
order2
item1
order3
item1
customer2
order_a
item_a1
item_a2
item_a3
Number of customers: 2
Number of orders: 4
Number of items: 6複製代碼
使用什麼都不作的空對象來代替 NULL。
一個方法返回 NULL,意味着方法的調用端須要去檢查返回值是不是 NULL,這麼作會致使很是多的冗餘的檢查代碼。而且若是某一個調用端忘記了作這個檢查返回值,而直接使用返回的對象,那麼就有可能拋出空指針異常。
Implementation
public abstract class AbstractOperation {
abstract void request();
}
public class RealOperation extends AbstractOperation {
@Override
void request() {
System.out.println("do something");
}
}
public class NullOperation extends AbstractOperation{
@Override
void request() {
// do nothing
}
}
public class Client {
public static void main(String[] args) {
AbstractOperation abstractOperation = func(-1);
abstractOperation.request();
}
public static AbstractOperation func(int para) {
if (para < 0) {
return new NullOperation();
}
return new RealOperation();
}
}複製代碼