Java的23种设计模式,详细讲解(二)
本人免费整理了Java高级资料,涵盖了Java、Redis、MongoDB、MySQL、Zookeeper、Spring Cloud、Dubbo高并发分布式等教程,一共30G,需要自己领取。
传送门:https://mp.weixin.qq.com/s/JzddfH-7yNudmkjT0IRL8Q
1. 责任链(Chain Of Responsibility)
Intent
使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链发送该请求,直到有一个对象处理它为止。
Class Diagram
- Handler:定义处理请求的接口,并且实现后继链(successor)
Implementation
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 handler1 = new ConcreteHandler1(null);
Handler handler2 = new ConcreteHandler2(handler1); Request request1 = new Request(RequestType.TYPE1, "request1");
handler2.handleRequest(request1); Request request2 = new Request(RequestType.TYPE2, "request2");
handler2.handleRequest(request2);
}
}
request1 is handle by ConcreteHandler1
request2 is handle by ConcreteHandler2
JDK
2. 命令(Command)
Intent
将命令封装成对象中,具有以下作用:
- 使用命令来参数化其它对象
- 将命令放入队列中进行排队
- 将命令的操作记录到日志中
- 支持可撤销的操作
Class Diagram
- Command:命令
- Receiver:命令接收者,也就是命令真正的执行者
- Invoker:通过它来调用命令
- Client:可以设置命令与命令的接收者
Implementation
设计一个遥控器,可以控制电灯开关。
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 Invoker {
private Command[] onCommands;
private Command[] offCommands;
private final int slotNum = 7; public Invoker() {
this.onCommands = new Command[slotNum];
this.offCommands = new Command[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) {
Invoker invoker = new Invoker();
Light light = new Light();
Command lightOnCommand = new LightOnCommand(light);
Command lightOffCommand = new LightOffCommand(light);
invoker.setOnCommand(lightOnCommand, 0);
invoker.setOffCommand(lightOffCommand, 0);
invoker.onButtonWasPushed(0);
invoker.offButtonWasPushed(0);
}
}
JDK
3. 解释器(Interpreter)
Intent
为语言创建解释器,通常由语言的语法和语法分析来定义。
Class Diagram
- TerminalExpression:终结符表达式,每个终结符都需要一个 TerminalExpression。
- Context:上下文,包含解释器之外的一些全局信息。
Implementation
以下是一个规则检验器实现,具有 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
JDK
- java.util.Pattern
- java.text.Normalizer
- All subclasses of java.text.Format
- javax.el.ELResolver
4. 迭代器(Iterator)
Intent
提供一种顺序访问聚合对象元素的方法,并且不暴露聚合对象的内部表示。
Class Diagram
- Aggregate 是聚合类,其中 createIterator() 方法可以产生一个 Iterator;
- Iterator 主要定义了 hasNext() 和 next() 方法。
- Client 组合了 Aggregate,为了迭代遍历 Aggregate,也需要组合 Iterator。
Implementation
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());
}
}
}
JDK
5. 中介者(Mediator)
Intent
集中相关对象之间复杂的沟通和控制方式。
Class Diagram
- Mediator:中介者,定义一个接口用于与各同事(Colleague)对象通信。
- Colleague:同事,相关对象
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 Calender extends Colleague {
@Override
public void onEvent(Mediator mediator) {
mediator.doEvent("calender");
} public void doCalender() {
System.out.println("doCalender()");
}
}
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 Calender calender;
private Sprinkler sprinkler; public ConcreteMediator(Alarm alarm, CoffeePot coffeePot, Calender calender, Sprinkler sprinkler) {
this.alarm = alarm;
this.coffeePot = coffeePot;
this.calender = calender;
this.sprinkler = sprinkler;
} @Override
public void doEvent(String eventType) {
switch (eventType) {
case "alarm":
doAlarmEvent();
break;
case "coffeePot":
doCoffeePotEvent();
break;
case "calender":
doCalenderEvent();
break;
default:
doSprinklerEvent();
}
} public void doAlarmEvent() {
alarm.doAlarm();
coffeePot.doCoffeePot();
calender.doCalender();
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();
Calender calender = new Calender();
Sprinkler sprinkler = new Sprinkler();
Mediator mediator = new ConcreteMediator(alarm, coffeePot, calender, sprinkler);
// 闹钟事件到达,调用中介者就可以操作相关对象
alarm.onEvent(mediator);
}
}
doAlarm()
doCoffeePot()
doCalender()
doSprinkler()
JDK
- 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()
6. 备忘录(Memento)
Intent
在不违反封装的情况下获得对象的内部状态,从而在需要时可以将对象恢复到最初状态。
Class Diagram
- Originator:原始对象
- Caretaker:负责保存好备忘录
- Menento:备忘录,存储原始对象的的状态。备忘录实际上有两个接口,一个是提供给 Caretaker 的窄接口:它只能将备忘录传递给其它对象;一个是提供给 Originator 的宽接口,允许它访问到先前状态所需的所有数据。理想情况是只允许 Originator 访问本备忘录的内部状态。
Implementation
以下实现了一个简单计算器程序,可以输入两个值,然后计算这两个值的和。备忘录模式允许将这两个值存储起来,然后在某个时刻用存储的状态进行恢复。
实现参考:Memento Pattern - Calculator Example - Java Sourcecode
/**
* 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
JDK
- java.io.Serializable
7. 观察者(Observer)
Intent
定义对象之间的一对多依赖,当一个对象状态改变时,它的所有依赖都会收到通知并且自动更新状态。
主题(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 WeatherStation {
public static void main(String[] args) {
WeatherData weatherData = new WeatherData();
CurrentConditionsDisplay currentConditionsDisplay = new CurrentConditionsDisplay(weatherData);
StatisticsDisplay statisticsDisplay = new StatisticsDisplay(weatherData); weatherData.setMeasurements(0, 0, 0);
weatherData.setMeasurements(1, 1, 1);
}
}
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
JDK
8. 状态(State)
Intent
允许对象在内部状态改变时改变它的行为,对象看起来好像修改了它所属的类。
Class Diagram
Implementation
糖果销售机有多种状态,每种状态下销售机有不同的行为,状态可以发生转移,使得销售机的行为也发生改变。
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
9. 策略(Strategy)
Intent
定义一系列算法,封装每个算法,并使它们可以互换。
策略模式可以让算法独立于使用它的客户端。
Class Diagram
- Strategy 接口定义了一个算法族,它们都实现了 behavior() 方法。
- Context 是使用到该算法族的类,其中的 doSomething() 方法会调用 behavior(),setStrategy(Strategy) 方法可以动态地改变 strategy 对象,也就是说能动态地改变 Context 所使用的算法。
与状态模式的比较
状态模式的类图和策略模式类似,并且都是能够动态改变对象的行为。但是状态模式是通过状态转移来改变 Context 所组合的 State 对象,而策略模式是通过 Context 本身的决策来改变组合的 Strategy 对象。所谓的状态转移,是指 Context 在运行过程中由于一些条件发生改变而使得 State 对象发生改变,注意必须要是在运行过程中。
状态模式主要是用来解决状态转移的问题,当状态发生转移了,那么 Context 对象就会改变它的行为;而策略模式主要是用来封装一组可以互相替代的算法族,并且可以根据需要动态地去替换 Context 使用的算法。
Implementation
设计一个鸭子,它可以动态地改变叫声。这里的算法族是鸭子的叫声行为。
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!
JDK
- java.util.Comparator#compare()
- javax.servlet.http.HttpServlet
- javax.servlet.Filter#doFilter()
10. 模板方法(Template Method)
Intent
定义算法框架,并将一些步骤的实现延迟到子类。
通过模板方法,子类可以重新定义算法的某些步骤,而不用改变算法的结构。
Class Diagram
Implementation
冲咖啡和冲茶都有类似的流程,但是某些步骤会有点不一样,要求复用那些相同步骤的代码。
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
JDK
- java.util.Collections#sort()
- java.io.InputStream#skip()
- java.io.InputStream#read()
- java.util.AbstractList#indexOf()
11. 访问者(Visitor)
Intent
为一个对象结构(比如组合结构)增加新能力。
Class Diagram
- Visitor:访问者,为每一个 ConcreteElement 声明一个 visit 操作
- ConcreteVisitor:具体访问者,存储遍历过程中的累计结果
- ObjectStructure:对象结构,可以是组合结构,或者是一个集合。
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
JDK
- javax.lang.model.element.Element and javax.lang.model.element.ElementVisitor
- javax.lang.model.type.TypeMirror and javax.lang.model.type.TypeVisitor
12. 空对象(Null)
Intent
使用什么都不做的空对象来代替 NULL。
一个方法返回 NULL,意味着方法的调用端需要去检查返回值是否是 NULL,这么做会导致非常多的冗余的检查代码。并且如果某一个调用端忘记了做这个检查返回值,而直接使用返回的对象,那么就有可能抛出空指针异常。
Class Diagram
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();
}
}
Java的23种设计模式,详细讲解(二)的更多相关文章
- JAVA:23种设计模式详解(转)
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java实现23种设计模式
一.设计模式的分类 总体来说设计模式分为三大类: 创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式. 结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接 ...
- Java 开发23种设计模式
设计模式(Design Patterns) ——可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了 ...
- Java的23种设计模式(转)
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于 ...
- Java的23种设计模式<一>
设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代 码可靠性. 毫无疑问,设计模式 ...
- Java基础-Java中23种设计模式之常用的设计模式
Java基础-Java中23种设计模式之常用的设计模式 作者:尹正杰 版权声明:原创作品,谢绝转载!否则将追究法律责任. 一.设计模式分类 设计模式是针对特定场景给出的专家级的解决方案.总的来说设 ...
- Java中23种设计模式(附代码样例)
一.设计模式分类总体来说设计模式分为三大类:创建型模式,共五种:工厂方法模式.抽象工厂模式.单例模式.建造者模式.原型模式.结构型模式,共七种:适配器模式.装饰器模式.代理模式.外观模式.桥接模式.组 ...
- 从追MM谈Java的23种设计模式(转)
从追MM谈Java的23种设计模式 这个是从某个文章转载过来的.但是忘了原文链接.如果知道的,我追加一下. 1.FACTORY-追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西 ...
- 从追MM谈Java的23种设计模式
从追MM谈Java的23种设计模式 1.FACTORY—追MM少不了请吃饭了,麦当劳的鸡翅和肯德基的鸡翅都是MM爱吃的东西,虽然口味有所不同,但不管你带MM去麦当劳或肯 德基,只管向服务员说“来四个鸡 ...
- java的23种设计模式之建造者模式
场景和本质 场景 本质 案例 原理 应用场景 场景和本质 场景 我们要建造一个复杂的产品.比如:神州飞船,Iphone.这个复杂的产品的创建.有这样一个问题需要处理:装配这些子组件是不是有个步骤问题? ...
随机推荐
- C语言程序设计100例之(21):折半查找
例21 折半查找 问题描述 顺序查找是一种最简单和最基本的检索方法.其基本思想是:从检索表的一端(如表中第一个记录或最后一个记录)开始,逐个进行记录的关键字和给定值的比较.若某个记录的关键字和给定值 ...
- SqlException:ConnectionTimeout Expired. The timeout period elapsed during the post-login phase
linux系统部署.netcore程序后,访问某台sqlserver 2008 R2数据库 Connection Timeout Expired. The timeout period elapsed ...
- 计算机组成原理——DMA存取方式
DMA(Direct Memory Access)直接存储器存取 高速大容量存储器和主存之间交换时,若采用程序直接传送或程序中断传送的方式,则会有如下问题发生. 1)采用程序直接传送,主机工作效 ...
- (转)python中用logging实现日志滚动和过期日志删除
转自:https://blog.csdn.net/ashi198866/article/details/46725813 logging库提供了两个可以用于日志滚动的class(可以参考https:/ ...
- NuGet 修改包路径
NuGet 是 .NET 平台下的一个免费.开源的包管理开发工具. 修改全局包管理目录 通过 NuGet 安装包时,NuGet 先将包下载至一个统一的目录,默认路径是:C:\Users\用户名\.nu ...
- layui table 分页 序号始终从”1“开始解决方法
在用Layui table 分页显示数据,用 type:"numbers" 进行显示序号有以下的问题 1.表格自带的分页,page:true 这种分页,在切换页面的时候序号可以正常 ...
- Thymeleaf常用语法:数据迭代
Thymeleaf数据迭代使用th:each属性,可以迭代数组.List.Set和Map等,数组.List.Set的迭代方法类似,迭代Map则会得到一个java.util.Map.Entry对象.在迭 ...
- 默认VS 下machine.config的位置
- GetPrivateProfileInt 使用方法
GetPrivateProfileInt =>从ini文件取得数值 <参数> lpApplicationName String,指定在其中查找条目的小节.注意这个字串是不区分大小写的 ...
- Jenkins实现单一安卓项目打包多个module填坑实录
今天接手一个任务,已有项目结构上新添加了一个module,这个module打包工作需要在Jenkins上添加一个方便测试点击的打包工程 因为之前已有现成的打包工程,我直接新建了一个工程并且复制原有工程 ...