使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。 将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
- Handler:定义处理请求的接口,并且实现后继链(successor)
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,这样就有利于随时切换新的实现; 其次每个处理请求对象只实现业务流程中的一步业务处理,这样使其变得简单; 最后职责链模式会动态的来组合这些处理请求的对象, 把它们按照流程动态组合起来,并要求它们依次调用,这样就动态的实现了流程。
将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
- Command:命令
- Receiver:命令接收者,也就是命令真正的执行者
- Invoker:通过它来调用命令
- Client:可以设置命令与命令的接收者
/**
* 接收者,其实是命令的真正执行者
*/
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();
}
}
设计一个遥控器,可以控制电灯开关。
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);
}
}
定义一个语法,定义一个解释器,该解释器处理该语法句子。
- TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
- Context:上下文,包含解释器之外的一些全局信息。
以下是一个规则检验器实现,具有 and 和 or 规则,通过规则可以构建一颗解析树,用来检验一个文本是否满足解析树定义的规则。
例如一颗解析树为 D And (A Or (B C)),文本 "D A" 满足该解析树定义的规则。
这里的 Context 指的是 String。
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.尽量不要在重要的模块中使用解释器模式
2.解释器在实际系统开发中使用较少
3.可以考虑使用开源的Expression4J、Jep等开源的解析工具包
- java.util.Pattern
- java.text.Normalizer
- All subclasses of java.text.Format
- javax.el.ELResolver
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
- Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
- Iterator 主要定义了 hasNext() 和 next() 方法。
- Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
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());
}
}
}
集中相关对象之间复杂的沟通和控制方式。
- Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
- Colleague:同事,相关对象
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()
- All scheduleXXX() methods of java.util.Timer
- java.util.concurrent.Executor#execute()
- submit() and invokeXXX() methods of java.util.concurrent.ExecutorService
- scheduleXXX() methods of java.util.concurrent.ScheduledExecutorService
- java.lang.reflect.Method#invoke()
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
- Originator:原始对象
- Caretaker:负责保存好备忘录
- Menento:备忘录,存储原始对象的的状态。 备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象; 一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。 备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。
/**
* 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
- java.io.Serializable
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(Subject)是被观察的对象,而其所有依赖者(Observer)称为观察者。
主题(Subject)具有注册和移除观察者、并通知所有观察者的功能,主题是通过维护一张观察者列表来实现这些操作的。
观察者(Observer)的注册功能需要调用主题的 registerObserver() 方法。
天气数据布告板会在天气信息发生改变时更新其内容,布告板有多个,并且在将来会继续增加。
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
定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。
- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。 但是状态模式是通过状态转移来改变 Context 所组合的 State 对象, 而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。 所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变, 注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为; 而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
报价管理:向客户报价,对于销售部门的人来讲,这是一个非常重大、非常复杂的问题,对不同的客户要报不同的价格,比如:
- 对普通客户或者是新客户报的是全价
- 对老客户报的价格,根据客户年限,给予一定的折扣
- 对大客户报的价格,根据大客户的累计消费金额,给予一定的折扣
/**
* 策略,定义计算报价算法的接口
*/
public interface Strategy {
/**
* 计算报价
* @param goodsPrice 商品原价
*/
void calcPrice(double goodsPrice);
}
public class NormalCustomerStrategy implements Strategy{
@Override
public void calcPrice(double goodsPrice) {
System.out.println("对于新客户或者是普通客户,没有折扣:"+goodsPrice);
}
}
public class OldCustomerStrategy implements Strategy{
@Override
public void calcPrice(double goodsPrice) {
System.out.println("对于老客户,统一折扣5%:"+goodsPrice*(1-0.05));
}
}
public class LargeCustomerStrategy implements Strategy{
@Override
public void calcPrice(double goodsPrice) {
System.out.println("对于大客户,统一折扣10%:"+goodsPrice*(1-0.1));
}
}
/**
* Context 是使用到该算法族的类,其中的 doSomething()方法会调用 behavior(),
* setStrategy(Strategy) 方法可以动态地改变 strategy 对象,
* 也就是说能动态地改变 Context 所使用的算法。
*/
public class Price {
private Strategy strategy;
public void price(double goodsPrice){
strategy.calcPrice(goodsPrice);
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
public class Client {
public static void main(String[] args) {
Price price = new Price();
price.setStrategy(new NormalCustomerStrategy());
price.price(1000.0);
price.setStrategy(new OldCustomerStrategy());
price.price(1000.0);
price.setStrategy(new LargeCustomerStrategy());
price.price(1000.0);
}
}
对于新客户或者是普通客户,没有折扣:1000.0
对于老客户,统一折扣5%:950.0
对于大客户,统一折扣10%:900.0
设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。
/**
* 策略
*/
public interface Strategy {
void behavior();
}
public class QuackStrategy implements Strategy{
@Override
public void behavior() {
System.out.println("quack!");
}
}
public class SqueakStrategy implements Strategy{
@Override
public void behavior() {
System.out.println("squeak!");
}
}
/**
* Context 是使用到该算法族的类,其中的 doSomething()方法会调用 behavior(),
* setStrategy(Strategy) 方法可以动态地改变 strategy 对象,
* 也就是说能动态地改变 Context 所使用的算法。
*/
public class Duck {
private Strategy strategy;
public void perform(){
if(strategy!=null){
strategy.behavior();
}
}
public void setStrategy(Strategy strategy) {
this.strategy = strategy;
}
}
public class Client {
public static void main(String[] args) {
Duck duck = new Duck();
duck.setStrategy(new QuackStrategy());
duck.perform();
duck.setStrategy(new SqueakStrategy());
duck.perform();
}
}
quack!
squeak!
- java.util.Comparator#compare()
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
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
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.util.AbstractList#indexOf()
为一个对象结构(比如组合结构)增加新能力。
- Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合。
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
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
使用什么都不做的空对象来代替 NULL。
一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
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();
}
}