java设计模式之行为型模式
1. 责任链模式(Chain of Responsibility Pattern)
特点:使多个对象都有机会处理请求,从而避免请求的发送者和接收者之间的耦合关系。将这些对象连成一条链,并沿着这条链传递请求,直到有一个对象处理它为止。
使用场景:
- 多个对象可以处理一个请求,具体由哪个对象处理在运行时决定。
- 在请求处理者不明确的情况下向多个对象中的一个提交请求。
代码示例:
interface Handler {
void handleRequest(int request);
}
class ConcreteHandler1 implements Handler {
private Handler nextHandler;
@Override
public void handleRequest(int request) {
if (request < 10) {
System.out.println("ConcreteHandler1 处理请求 " + request);
} else {
if (nextHandler!= null) {
nextHandler.handleRequest(request);
}
}
}
public void setNextHandler(Handler nextHandler) {
this.nextHandler = nextHandler;
}
}
class ConcreteHandler2 implements Handler {
@Override
public void handleRequest(int request) {
if (request >= 10 && request < 20) {
System.out.println("ConcreteHandler2 处理请求 " + request);
}
}
}
public class ChainOfResponsibilityPattern {
public static void main(String[] args) {
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
handler1.setNextHandler(handler2);
handler1.handleRequest(5);
handler1.handleRequest(15);
}
}
优点:
- 降低了发送者和接收者之间的耦合。
- 增强了给对象指派职责的灵活性。
缺点:
- 不能保证请求一定被处理。
- 可能会导致系统性能下降,因为请求可能在链中传递的过程较长。
2. 命令模式(Command Pattern)
特点:将一个请求封装为一个对象,从而使你可用不同的请求对客户进行参数化;对请求排队或记录请求日志,以及支持可撤销的操作。
使用场景:
- 需要将请求调用者和请求执行者解耦。
- 需要支持撤销、恢复操作。
代码示例:
interface Command {
void execute();
}
class ConcreteCommand implements Command {
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
this.receiver = receiver;
}
@Override
public void execute() {
receiver.action();
}
}
class Receiver {
public void action() {
System.out.println("执行具体操作");
}
}
class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void invoke() {
command.execute();
}
}
public class CommandPattern {
public static void main(String[] args) {
Receiver receiver = new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.invoke();
}
}
优点:
- 降低了系统的耦合度。
- 新的命令可以很容易地添加到系统中。
缺点:
- 可能会导致系统中有过多的具体命令类。
3. 解释器模式(Interpreter Pattern)
特点:给定一个语言,定义它的文法的一种表示,并定义一个解释器,这个解释器使用该表示来解释语言中的句子。
使用场景:
- 当有一个语言需要解释执行,并且语言中的文法较为简单时。
代码示例:
interface Expression {
int interpret();
}
class NumberExpression implements Expression {
private int number;
public NumberExpression(int number) {
this.number = number;
}
@Override
public int interpret() {
return number;
}
}
class AddExpression implements Expression {
private Expression left;
private Expression right;
public AddExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public int interpret() {
return left.interpret() + right.interpret();
}
}
public class InterpreterPattern {
public static void main(String[] args) {
Expression five = new NumberExpression(5);
Expression three = new NumberExpression(3);
Expression sum = new AddExpression(five, three);
System.out.println(sum.interpret());
}
}
优点:
- 易于改变和扩展文法。
- 增加了新的解释表达式的方式较为容易。
缺点:
- 对于复杂的文法,可能会导致类层次变得庞大且复杂。
- 解释器模式的效率通常较低。
4. 迭代器模式(Iterator Pattern)
特点:提供一种方法顺序访问一个聚合对象中各个元素,而又不需暴露该对象的内部表示。
使用场景:
- 访问一个聚合对象的内容而无需暴露它的内部表示。
- 为遍历不同的聚合结构提供一个统一的接口。
代码示例:
interface Iterator {
boolean hasNext();
Object next();
}
class ConcreteIterator implements Iterator {
private List<String> list;
private int index;
public ConcreteIterator(List<String> list) {
this.list = list;
this.index = 0;
}
@Override
public boolean hasNext() {
return index < list.size();
}
@Override
public Object next() {
if (hasNext()) {
return list.get(index++);
}
return null;
}
}
class Aggregate {
private List<String> items = new ArrayList<>();
public void addItem(String item) {
items.add(item);
}
public Iterator createIterator() {
return new ConcreteIterator(items);
}
}
public class IteratorPattern {
public static void main(String[] args) {
Aggregate aggregate = new Aggregate();
aggregate.addItem("Item 1");
aggregate.addItem("Item 2");
aggregate.addItem("Item 3");
Iterator iterator = aggregate.createIterator();
while (iterator.hasNext()) {
System.out.println(iterator.next());
}
}
}
优点:
- 支持以不同的方式遍历一个聚合对象。
- 简化了聚合类的接口。
缺点:
- 对于某些复杂的迭代逻辑,可能会增加代码的复杂性。
5. 中介者模式(Mediator Pattern)
特点:用一个中介对象来封装一系列的对象交互。中介者使各对象不需要显式地相互引用,从而使其耦合松散,而且可以独立地改变它们之间的交互。
使用场景:
- 一组对象以定义良好但是复杂的方式进行通信,产生的相互依赖关系结构混乱且难以理解。
- 一个对象引用其他很多对象并且直接与这些对象通信,导致难以复用该对象。
代码示例:
interface Mediator {
void notifyColleagues();
}
class ConcreteMediator implements Mediator {
private Colleague1 colleague1;
private Colleague2 colleague2;
public void setColleague1(Colleague1 colleague1) {
this.colleague1 = colleague1;
}
public void setColleague2(Colleague2 colleague2) {
this.colleague2 = colleague2;
}
@Override
public void notifyColleagues() {
colleague1.action();
colleague2.action();
}
}
class Colleague1 {
private Mediator mediator;
public Colleague1(Mediator mediator) {
this.mediator = mediator;
}
public void action() {
System.out.println("Colleague1 执行操作");
}
}
class Colleague2 {
private Mediator mediator;
public Colleague2(Mediator mediator) {
this.mediator = mediator;
}
public void action() {
System.out.println("Colleague2 执行操作");
}
}
public class MediatorPattern {
public static void main(String[] args) {
ConcreteMediator mediator = new ConcreteMediator();
Colleague1 colleague1 = new Colleague1(mediator);
Colleague2 colleague2 = new Colleague2(mediator);
mediator.setColleague1(colleague1);
mediator.setColleague2(colleague2);
mediator.notifyColleagues();
}
}
优点:
- 减少了对象之间的耦合,使对象之间的关系更加松散。
- 集中控制交互,使系统更易于维护和扩展。
缺点:
- 中介者类可能会变得过于复杂,承担过多的责任。
6. 备忘录模式(Memento Pattern)
特点:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
使用场景:
- 必须保存一个对象在某一时刻的状态,以便在需要时能恢复到这个状态。
- 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
代码示例:
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void restoreStateFromMemento(Memento memento) {
state = memento.getState();
}
}
class Caretaker {
private Memento memento;
public void saveMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoPattern {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("State 1");
caretaker.saveMemento(originator.saveStateToMemento());
originator.setState("State 2");
originator.restoreStateFromMemento(caretaker.getMemento());
}
}
优点:
- 保持了封装边界,不会暴露对象的内部实现细节。
- 可以方便地实现撤销和恢复操作。
缺点:
- 如果类的内部状态过多,可能会导致备忘录类变得庞大。
7. 观察者模式(Observer Pattern)
特点:定义对象间的一种一对多的依赖关系,当一个对象的状态发生改变时,所有依赖于它的对象都得到通知并被自动更新。
使用场景:
- 当一个对象的改变需要同时改变其他对象,且不知道具体有多少对象需要改变时。
- 当一个对象必须通知其他对象,而又希望这个对象和其他被通知的对象是松耦合的。
代码示例:
interface Observer {
void update(String message);
}
class ConcreteObserver1 implements Observer {
@Override
public void update(String message) {
System.out.println("ConcreteObserver1 收到消息: " + message);
}
}
class ConcreteObserver2 implements Observer {
@Override
public void update(String message) {
System.out.println("ConcreteObserver2 收到消息: " + message);
}
}
class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer) {
observers.add(observer);
}
public void detach(Observer observer) {
observers.remove(observer);
}
public void notifyObservers(String message) {
for (Observer observer : observers) {
observer.update(message);
}
}
}
public class ObserverPattern {
public static void main(String[] args) {
Subject subject = new Subject();
Observer observer1 = new ConcreteObserver1();
Observer observer2 = new ConcreteObserver2();
subject.attach(observer1);
subject.attach(observer2);
subject.notifyObservers("消息更新");
}
}
优点:
- 实现了表示层和数据逻辑层的分离。
- 支持广播通信,观察者可以接收多个主题的通知。
缺点:
- 如果观察者过多,通知的开销可能会很大。
- 观察者和主题之间存在着一定的耦合。
8. 状态模式(State Pattern)
特点:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
使用场景:
- 一个对象的行为取决于它的状态,并且它必须在运行时刻根据状态改变它的行为。
- 一个操作中含有庞大的多分支的条件语句,且这些分支依赖于该对象的状态。
代码示例:
interface State {
void handle(Context context);
}
class ConcreteStateA implements State {
@Override
public void handle(Context context) {
System.out.println("处于状态 A");
context.setState(new ConcreteStateB());
}
}
class ConcreteStateB implements State {
@Override
public void handle(Context context) {
System.out.println("处于状态 B");
context.setState(new ConcreteStateA());
}
}
class Context {
private State state;
public Context() {
state = new ConcreteStateA();
}
public void setState(State state) {
this.state = state;
}
public void request() {
state.handle(this);
}
}
public class StatePattern {
public static void main(String[] args) {
Context context = new Context();
context.request();
context.request();
}
}
优点:
- 状态的切换逻辑被封装在状态类中,易于理解和维护。
- 消除了庞大的条件分支语句。
缺点:
- 可能会导致系统中类的数量增加。
9. 策略模式(Strategy Pattern)
特点:定义一系列的算法,把它们一个个封装起来,并且使它们可相互替换。策略模式使得算法可独立于使用它的客户而变化。
使用场景:
- 多个类只区别在表现行为不同,可以使用策略模式,在运行时动态选择具体要执行的行为。
- 需要在不同情况下使用不同的算法。
代码示例:
interface Strategy {
int doOperation(int num1, int num2);
}
class ConcreteStrategyAdd implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 + num2;
}
}
class ConcreteStrategySubtract implements Strategy {
@Override
public int doOperation(int num1, int num2) {
return num1 - num2;
}
}
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int executeStrategy(int num1, int num2) {
return strategy.doOperation(num1, num2);
}
}
public class StrategyPattern {
public static void main(String[] args) {
Context context1 = new Context(new ConcreteStrategyAdd());
int result1 = context1.executeStrategy(5, 3);
Context context2 = new Context(new ConcreteStrategySubtract());
int result2 = context2.executeStrategy(5, 3);
System.out.println("加法结果: " + result1);
System.out.println("减法结果: " + result2);
}
}
优点:
- 算法可以自由切换。
- 避免使用多重条件判断。
- 扩展性良好。
缺点:
- 客户端必须知道所有的策略类,并自行决定使用哪一个策略类。
- 策略类会增多。
10. 模板方法模式(Template Method Pattern)
特点:定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模板方法使得子类可以在不改变算法结构的情况下重定义算法的某些特定步骤。
使用场景:
- 当存在多个子类共有的算法逻辑,但其中一些具体步骤在子类中有所不同时。
- 一次性实现一个算法的不变部分,并将可变的行为留给子类来实现。
代码示例:
abstract class AbstractClass {
// 模板方法,定义算法骨架
public void templateMethod() {
method1();
method2();
}
// 抽象方法,由子类实现
abstract void method1();
// 抽象方法,由子类实现
abstract void method2();
}
class ConcreteClass1 extends AbstractClass {
@Override
void method1() {
System.out.println("ConcreteClass1 实现 method1");
}
@Override
void method2() {
System.out.println("ConcreteClass1 实现 method2");
}
}
class ConcreteClass2 extends AbstractClass {
@Override
void method1() {
System.out.println("ConcreteClass2 实现 method1");
}
@Override
void method2() {
System.out.println("ConcreteClass2 实现 method2");
}
}
public class TemplateMethodPattern {
public static void main(String[] args) {
AbstractClass class1 = new ConcreteClass1();
class1.templateMethod();
AbstractClass class2 = new ConcreteClass2();
class2.templateMethod();
}
}
优点:
- 封装了不变部分,扩展可变部分。
- 提取公共代码,减少代码冗余。
缺点:
- 每一个不同的实现都需要一个子类来实现,导致类的数量增加。
- 可能会限制某些子类的灵活性,因为父类已经规定了算法的骨架。
11. 访问者模式(Visitor Pattern)
特点:表示一个作用于某对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作。
使用场景:
- 一个对象结构包含很多类对象,它们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作。
- 需要对一个对象结构中的对象进行很多不同的并且不相关的操作,而你想避免让这些操作“污染”这些对象的类。
代码示例:
interface Visitor {
void visitElementA(ElementA elementA);
void visitElementB(ElementB elementB);
}
class ConcreteVisitor implements Visitor {
@Override
public void visitElementA(ElementA elementA) {
System.out.println("对 ElementA 进行具体访问操作");
}
@Override
public void visitElementB(ElementB elementB) {
System.out.println("对 ElementB 进行具体访问操作");
}
}
interface Element {
void accept(Visitor visitor);
}
class ElementA implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitElementA(this);
}
}
class ElementB implements Element {
@Override
public void accept(Visitor visitor) {
visitor.visitElementB(this);
}
}
public class VisitorPattern {
public static void main(String[] args) {
Visitor visitor = new ConcreteVisitor();
Element elementA = new ElementA();
Element elementB = new ElementB();
elementA.accept(visitor);
elementB.accept(visitor);
}
}
优点:
- 增加新的操作很容易,无需修改现有代码结构。
- 集中相关的操作而分离无关的操作。
缺点:
- 增加新的数据结构变得困难。
- 违反了依赖倒置原则,访问者依赖于具体的元素类。
12. 备忘录模式(Memento Pattern)
特点:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
使用场景:
- 必须保存一个对象在某一时刻的状态,以便在需要时能恢复到这个状态。
- 如果用一个接口来让其他对象得到这些状态,将会暴露对象的实现细节并破坏对象的封装性。
代码示例:
class Memento {
private String state;
public Memento(String state) {
this.state = state;
}
public String getState() {
return state;
}
}
class Originator {
private String state;
public void setState(String state) {
this.state = state;
}
public String getState() {
return state;
}
public Memento saveStateToMemento() {
return new Memento(state);
}
public void restoreStateFromMemento(Memento memento) {
state = memento.getState();
}
}
class Caretaker {
private Memento memento;
public void saveMemento(Memento memento) {
this.memento = memento;
}
public Memento getMemento() {
return memento;
}
}
public class MementoPattern {
public static void main(String[] args) {
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState("初始状态");
caretaker.saveMemento(originator.saveStateToMemento());
originator.setState("修改后的状态");
originator.restoreStateFromMemento(caretaker.getMemento());
}
}
优点:
- 保持了封装边界,不会暴露对象的内部实现细节。
- 可以方便地实现撤销和恢复操作。
缺点:
- 如果类的内部状态过多,可能会导致备忘录类变得庞大。