感言:今天这篇行为型设计模式写完了,就写了三篇设计模式相关文章了,完成了设计模式的部分学习了。每一个设计模式自己都写了一个很小的Demo,当然这些Demo也是参考了很多其他人写的博客以及一些书籍汇总产生的。总体来说给我的感觉是我面向对象的抽象能力有了很大的提升。对于接口,继承,封装等有了更加深入的理解,但是坦率的讲自己对设计模式的理解还不够强,还需得有更多的实践来将理论上的东西进行进一步的落实。
行为型模式:行为型模式设计到了算法和对象间职责的分配,行为模式描述了对象和类的模式,以及他们的通信模式,行为模式刻画了在程序运行时难以跟踪的复杂复杂的控制流可以分为行为类模式和行为类对象模式。将程序解耦,达到使系统升级性和维护性提高的目的。
行为型模式共有11种,分别对11种进行一个介绍 :
- 策略模式(Strategy)
- 模板方法模式(Template)
- 观察者模式(Observer)
- 迭代子模式(Iterator)
- 责任链模式(Chain of Responsibility)
- 命令模式(Command)
- 备忘录模式(memento)
- 状态模式(State)
- 访问者模式(Visitor)
- 中介者模式(Mediator)
- 解释器模式(Interpreter)
策略模式(Strategy Pattern):
在策略模式中,我们创建表示各种策略的对象和一个行为随着策略对象改变而改变的Context对象。
策略对象改变 context 对象的执行算法。
//创建接口Strategy,里面具有一个操作的function
public interface Strategy {
public int Operation(int left,int right);
}
//实现Strategy 接口
public class MultiplyOperation implements Strategy{
@Override
public int Operation(int left, int right) {
return left*right;
}
}
public class SubstractOperation implements Strategy{
@Override
public int Operation(int left, int right) {
return left-right;
}
}
//Context 会调用Strategy的Operation
public class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public int execute(int left,int right){
return strategy.Operation(left,right);
}
}
public class Demo {
public static void main(String[] args){
int left = 5;
int right = 10;
Context context=new Context(new AddOperation());
System.out.println("Use add operation left+right = "+context.execute(left,right));
context = new Context(new SubstractOperation());
System.out.println("Use substract operation left-right = "+context.execute(left,right));
}
}
//console输出
Use add operation left+right = 15
Use substract operation left-right = -5
分析:
我们使用Context类进行计算,但是我们给他传入了不同的计算算法进去。过程都是一样的。策略模式可以让客户端传入计算的算法,方便合理的去替换和增加算法。我们都调用的是Context.execute函数,当我们传入AddOperation和Substract Operation的时候参生了不同的结果。
模板方法模式(Template Pattern):
一个抽象类公开定义执行方法的方式/模板。他的子类可以按需要进行重写方法实现,但是调用将以抽象类中定义的方式进行。
//定义抽象函数Template 几个抽象方法和
一个调用几个抽象方法的类
public abstract class Template {
abstract void weakUp();
abstract void lunch();
abstract void sleep();
public final void holdDay(){
weakUp();
lunch();
sleep();
}
}
public class Cat extends Template{
@Override
void weakUp() {
System.out.println("I am cat weak up at the evening");
}
@Override
void lunch() {
System.out.println("I eat mouse");
}
@Override
void sleep() {
System.out.println("I sleep in the morning");
}
}
public class Pig extends Template{
@Override
void weakUp() {
System.out.println("I am Pig,I weak up in the morning");
}
@Override
void lunch() {
System.out.println("I can eat everything in the afternoon");
}
@Override
void sleep() {
System.out.println("I sleep after lunch");
}
}
public class Demo {
public static void main(String[] args){
Template cat =new Cat();
Template pig =new Pig();
cat.holdDay();
System.out.println();
pig.holdDay();
}
}
//输出结果
I am cat weak up at the evening
I eat mouse
I sleep in the morning
I am Pig,I weak up in the morning
I can eat everything in the afternoon
I sleep after lunch
分析:
定义了模板方法,定义了三个抽象函数,weakup,lunch,sleep ,和对外提供的一个函数holeday。子类cat和pig都继承于模板。然后都实现了抽象函数,然后再Demo里面我们可以看到调用Cat对象和Pig对象的holdDay最后就会有不同的结果。
观察者模式(Observer):
又时又被称为发布订阅模式,模型-视图模式。主要是当一个对象和多个对象存在关系时,一个对象发出消息。其他的对象都能够接收到消息并进行相应的处理。
public abstract class Observer {
protected Subject subject;
public abstract void update(String message);
}
public class ManObserver extends Observer{
public ManObserver(Subject subject) {
this.subject = subject;
}
@Override
public void update(String message) {
if(message.equalsIgnoreCase("man")){
System.out.println("我是男人,我接受到消息");
}else {
System.out.println("我是男人,我接到到消息,但是不做任何事情");
}
}
}
public class WomenObserver extends Observer{
public WomenObserver(Subject subject) {
this.subject = subject;
}
@Override
public void update(String message) {
if(message.equalsIgnoreCase("man")){
System.out.println("我是女人,我接受到消息,但是不做任何事情");
}else {
System.out.println("我是女人,我接到到消息");
}
}
}
public class Subject {
private List<Observer> observers = new ArrayList<>();
public void attach(Observer observer){
observers.add(observer);
}
public void notifyAllObservers(String message){
for(Observer observer:observers){
observer.update(message);
}
}
}
public class Demo {
public static void main(String[] args){
Subject subject =new Subject();
ManObserver manObserver =new ManObserver(subject);
subject.attach(manObserver);
WomenObserver womenObserver=new WomenObserver(subject);
subject.attach(womenObserver);
subject.notifyAllObservers("man");
System.out.println("---------");
subject.notifyAllObservers("woman");
}
}
//输出结果
我是男人,我接受到消息
我是女人,我接受到消息,但是不做任何事情
---------
我是男人,我接到到消息,但是不做任何事情
我是女人,我接到到消息
分析:
有两个观察者,他们都去订阅Subject的内容。当Subject有消息通知观察者的时候,观察者就能够获取到消息并做相应的处理。Subject对象有两个观察者,而且当他通知给man观察者的时候。woman观察者接受到了消息,但是不做任何操作。man观察者接受到了消息就做了相应的操作。输出的结果也很预期一致。(看我博客Spring-boot使用Quartz实现多线程调度任务 当中就用到了观察者模式进行处理)
迭代子模式(Iterator):
用于顺序访问集合对象的元素,不需要知道集合对象的底层表示。
public interface Container {
public Iterator getIterator();
}
public interface Iterator {
public boolean hasNext();
public Object next();
}
public class NameRepository implements Container{
public String names[] = {"Robert","John","Julie","Lora"};
@Override
public Iterator getIterator(){
return new NameIterator();
}
private class NameIterator implements Iterator{
int index;
@Override
public boolean hasNext(){
if(index<names.length){
return true;
}
return false;
}
@Override
public Object next(){
if(this.hasNext()){
return names[index++];
}
return null;
}
}
}
public class Demo {
public static void main(String[] args){
NameRepository nameRepository = new NameRepository();
for(Iterator iterator=nameRepository.getIterator();iterator.hasNext();){
String name = (String) iterator.next();
System.out.println("Name : " + name);
}
}
}
分析:
自己实现了一个Iterator来遍历数组。
责任链模式(Chain of Responsibilty Pattern):
为请求创建了一个接收者对象链,按照接受者对象依次运行。
//用JAVA常用的日志来说明问题
public abstract class AbstractLogger {
//定义3种优先级的日志
public static int INFO = 1;
public static int DEBUG = 2;
public static int ERROR = 3;
protected int level;
protected AbstractLogger nextLogger;
public void setNextLogger(AbstractLogger nextLogger){
this.nextLogger = nextLogger;
}
public void logMessage(int level,String message){
if(this.level<=level){
write(message);
}
if(nextLogger!=null){
nextLogger.logMessage(level,message);
}
}
abstract protected void write(String message);
}
//创建3个类,分别继承抽象类,实现抽象方法
public class ConsoleLogger extends AbstractLogger{
public ConsoleLogger(int level){
this.level = level;
}
@Override
protected void write(String message){
System.out.println("Standard Console:Logger"+message);
}
}
public class DebugLogger extends AbstractLogger{
public DebugLogger(int level){
this.level = level;
}
@Override
protected void write(String message){
System.out.println("Debug logger:Logger" + message);
}
}
public class ErrorLogger extends AbstractLogger{
public ErrorLogger(int level){
this.level = level;
}
protected void write(String message){
System.out.println("Error Console:Logger"+message);
}
}
public class Demo {
public static AbstractLogger getChainOfLoggers(){
AbstractLogger console = new ConsoleLogger(AbstractLogger.INFO);
AbstractLogger debug = new DebugLogger(AbstractLogger.DEBUG);
AbstractLogger error = new ErrorLogger(AbstractLogger.ERROR);
error.setNextLogger(debug);
debug.setNextLogger(console);
return error;
}
public static void main(String[] args){
AbstractLogger loggerChain = getChainOfLoggers();
loggerChain.logMessage(AbstractLogger.INFO,"This is info level");
loggerChain.logMessage(AbstractLogger.DEBUG,"This is debug level");
loggerChain.logMessage(AbstractLogger.ERROR,"This is error level");
}
}
//输出结果
Standard Console:LoggerThis is info level
Debug logger:LoggerThis is debug level
Standard Console:LoggerThis is debug level
Error Console:LoggerThis is error level
Debug logger:LoggerThis is error level
Standard Console:LoggerThis is error level
分析:定义了3种优先级的Logger,然后通过判断Logger的优先级来判断是否输出结果。当优先级高时就会多次输出结果,就像链一样,一个一个的挨着去比较,如果合适就进行相应的操作。在Spring中的Interceptor也是采用这种模式。(Spring和其他的大型框架里面将设计模式用得比较的透彻。我们将谁急模式学习好了,在看和理解一下大型的框架时就能够更好的去理解了。)
命令模式(Command Pattern):
它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
//接口Command
public interface Command {
void execute();
}
//Command实现类
public class ConcreteCommand implements Command{
private Receiver receiver = null;
public ConcreteCommand(Receiver receiver){
this.receiver =receiver;
}
@Override
public void execute(){
receiver.action();
}
}
//请求者
public class Invoker {
private Command command=null;
public Invoker(Command command){
this.command = command;
}
public void action(){
command.execute();
}
}
//接受者
public class Receiver {
public void action(){
System.out.println("执行操作");
}
}
public class Demo {
public static void main(String[] args){
Receiver receiver=new Receiver();
Command command = new ConcreteCommand(receiver);
Invoker invoker = new Invoker(command);
invoker.action();
}
}
分析:Demo里面,调用者将命令传进入,然后执行Action动作。由Command的receiver来执行相应的操作。这种模式可以让我们分离开命令行里面的If else判断。在我们需要自己去定义一些命令的时候,这种实现方式非常有效。
备忘录模式(memetno Pattern):
备忘录模式这个很好理解,我们在生活中经常会使用到的,比如写代码,写了很多,发现思路错了,想回到之前的代码,我们在IDE里面就可以使用Ctrl+Z进行撤销。事实上IDE对我们的每个动作都进行了记录,当我们撤销时就回到上一个记录。那么我们也可以自己实现一个备忘录,这种模式是非常有用而且有效的。
public class Memento {
private String state;
public Memento(String state){
this.state = state;
}
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
}
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento saveStateToMemento(){
return new Memento(state);
}
public void getStateFromMemento(Memento memento){
this.state = memento.getState();
}
}
public class CareTaker {
public Stack<Memento> mementos = new Stack<>();
public void add(Memento memento){
this.mementos.push(memento);
}
public Memento repeal(){
return mementos.pop();
}
}
public class Demo {
public static void main(String[] args){
Originator originator =new Originator();
CareTaker careTaker = new CareTaker();
originator.setState("第一次操作");
careTaker.add(originator.saveStateToMemento());
originator.setState("第二次操作");
careTaker.add(originator.saveStateToMemento());
originator.setState("第三次操作");
careTaker.add(originator.saveStateToMemento());
originator.getStateFromMemento(careTaker.repeal());
System.out.println(originator.getState());
originator.getStateFromMemento(careTaker.repeal());
System.out.println(originator.getState());
originator.getStateFromMemento(careTaker.repeal());
System.out.println(originator.getState());
}
}
//输出
第三次操作
第二次操作
第一次操作
分析:
CareTake对Originator的操作进行做记录放入到Stack中,当orginator想要撤销回到上一步的时候,就可以调用CareTake的撤销函数,回到上一次的现场进行操作。但是备忘录模式会如果一直记录会消耗大量的内存。所以我们可以给备忘录设置最大的备忘次数。超过之后就将很久以前的舍去。
状态模式(State Pattern):
在状态模式中,我们创建表示各种状态的对象和一个行为随着状态对象改变而改变的 context 对象。
public class Context {
private State state;
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void enchashment(){
state.enchashment();
}
}
public interface State {
public void enchashment();
}
public class LegalState implements State{
@Override
public void enchashment() {
System.out.println("我是合法账号,取钱没问题");
}
}
public class OverdraftState implements State{
@Override
public void enchashment() {
System.out.println("我是透支账号,无法取现");
}
}
public class Demo {
public static void main(String[] args){
Context context =new Context();
context.setState(new LegalState());
context.enchashment();
context.setState(new OverdraftState());
context.enchashment();
}
}
分析:
当Context设置的状态是合法的时候。调用取现就可以正确的取现。当Context设置状态是透支状态的时候取现就出现了异常。将LegalState和Overdraft的处理给了各自的对象。而不是由Context来进行处理。
访问者模式(Visitor Pattern):
我们使用了一个访问者类,它改变了元素类的执行算法。通过这种方式,元素的执行算法可以随着访问者改变而改变。这种类型的设计模式属于行为型模式。根据模式,元素对象已接受访问者对象,这样访问者对象就可以处理元素对象上的操作。
public interface ComputerPart {
public void accept(ComputerPartVisitor computerPartVisitor);
}
public class Computer implements ComputerPart{
ComputerPart[] parts;
public Computer(){
parts = new ComputerPart[]{
new Mouse(),
new Keyboard(),
new Monitor()
};
}
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
for(int i=0;i< parts.length;i++){
parts[i].accept(computerPartVisitor);
}
computerPartVisitor.visit(this);
}
}
public class ComputerPartDisplayVisitor implements ComputerPartVisitor{
@Override
public void visit(Computer computer) {
System.out.println("Display computer");
}
@Override
public void visit(Mouse mouse) {
System.out.println("Display mouse");
}
@Override
public void visit(Keyboard keyboard) {
System.out.println("Display keyboard");
}
@Override
public void visit(Monitor monitor) {
System.out.println("Display monitor");
}
}
public interface ComputerPartVisitor {
public void visit(Computer computer);
public void visit(Mouse mouse);
public void visit(Keyboard keyboard);
public void visit(Monitor monitor);
}
public class Keyboard implements ComputerPart{
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Monitor implements ComputerPart{
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Mouse implements ComputerPart{
@Override
public void accept(ComputerPartVisitor computerPartVisitor) {
computerPartVisitor.visit(this);
}
}
public class Demo {
public static void main(String[] args){
ComputerPart computer=new Computer();
computer.accept(new ComputerPartDisplayVisitor());
}
}
解释器模式(interpreter Pattern):
提供了评估语言的语法或表达式的方式,它属于行为型模式。这种模式实现了一个表达式接口,该接口解释一个特定的上下文。这种模式被用在 SQL 解析、符号处理引擎等。
public interface Expression {
public boolean interpret(String context);
}
public class AndExpression implements Expression{
private Expression left;
private Expression right;
public AndExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(String context) {
return left.interpret(context)&&right.interpret(context);
}
}
public class OrExpression implements Expression{
private Expression left;
private Expression right;
public OrExpression(Expression left, Expression right) {
this.left = left;
this.right = right;
}
@Override
public boolean interpret(String context) {
return left.interpret(context)||right.interpret(context);
}
}
public class TerminalExpression implements Expression{
private String data;
public TerminalExpression(String data){
this.data = data;
}
@Override
public boolean interpret(String context) {
if(context.contains(data)){
return true;
}
return false;
}
}
package com.opensource.jiangbiao.behavior.interpreter;
public class Demo {
public static Expression getMale(){
Expression jiangbiao = new TerminalExpression("jiangbiao");
Expression zhangshan = new TerminalExpression("zhangshan");
return new OrExpression(jiangbiao,zhangshan);
}
public static Expression getMarriedWomen(){
Expression wangmeimei = new TerminalExpression("wangmeimei");
Expression married =new TerminalExpression("married");
return new AndExpression(wangmeimei,married);
}
public static void main(String[] args){
Expression male = getMale();
System.out.println("jiangbiao is a male: "+male.interpret("jiangbiao"));
Expression marriedFemale = getMarriedWomen();
System.out.println("Wangmeimei is a married woman :"+getMarriedWomen().interpret("married wangmeimei"));
}
}
分析:解释器模式是用来对语法进行分析。比如(A&&B||C&&B)这种语法数是可以很好的用解释器模式来进行过滤分析的。
注:本博客所用的实例代码都会放在Github供大家下载学习。
地址:https://github.com/standup-jb/DesignPattern.git
知乎主页:点击关注我知乎
如果可以愿意分享自己的见解或者添加更多更好的实例代码,可以联系我。谢谢。
相关博客:设计模式:创建型模式(一)