写点什么

Java 中 23 种设计模式详解:详细分析 11 种行为型模式

发布于: 3 小时前
Java中23种设计模式详解:详细分析11种行为型模式

行为型模式

  • 11 种行为模式的关系:

  • 第一类: 通过父类与子类的关系进行实现

  • 第二类: 通过两个类之间的关系进行实现

  • 第三类: 通过类的状态进行实现

  • 第四类: 通过中间类进行实现

策略模式(Strategy)

  • 策略模式:

  • 定义了一系列算法,并将每个算法封装起来,可以相互替换,算法的变化不会影响到使用算法的用户

  • 设计一个接口,为一系列实现类提供统一的方法,多个实现类实现该接口

  • 设计一个抽象类(选用,作为辅助类),提供辅助函数

  • ICalculator 接口提供统一的方法

  • AbstractCalculator 是抽象辅助类,提供辅助方法


- ICalculatorpublic interface ICalculator{  public int calculate(String exp);}



- AbstractCalculatorpublic abstract class AbstractCalcuator{ public int[] split(String exp,String opt){ String array[]=exp.split(opt); int arrayInt[]=new int[2]; arrayInt[0]=Integer.parseInt(array[0]); arrayInt[1]=Integer.parseInt(array[1]);
return arrayInt; }}



- Pluspublic class Plus extends AbstractCalculator implements ICalculator{ @Override public int calculate(String exp){ int arrayInt[]=split(exp,"\\+"); return arrayInt[0]+arrayInt[1]; }}


- Minuspublic class Minus extends AbstractCalculator implements ICalculator{ @Override public int calculate(String exp){ int arrayInt[]=split(exp,"-"); return arrayInt[0]-arrayInt[1]; } }



- Multiplypublic class Multiply extends AbstractCalculator implements ICalculator{ @Override public int calculate(String exp){ int arrayInt[]=split(exp,"\\*"); return arrayInt[0]*arrayInt[1]; }}



- StrategyTestpublic class StrategyTest{ public static void mian(String[] args){ String exp="2+8"; ICalculator cal=new Plus(); int result=cal.calculate(exp); System.out.println(result); }}
复制代码


  • 策略模式的决定权在于用户:

  • 系统本身提供不同算法的实现

  • 新增或删除算法

  • 对各种算法做封装

  • 策略模式多用在算法决策系统中,外部用户只需要决定使用哪一个算法即可

模板方法模式(Template Method)

  • 模板方法模式:

  • 一个抽象类中,定义一个主方法

  • 再定义无数个方法,可以是抽象的,也可以是实际的方法

  • 定义一个子类,继承抽象类,重写抽象类中的方法

  • 通过调用抽象类,实现对子类的调用

  • AbstractCalculator 类中定义一个主方法 calculate()

  • calculate() 调用 split()

  • Plus Minus 分别继承 AbstractCalculator

  • 通过对 AbstractCalculator 的调用实现对子类的调用


public abstract class AbstractCalculator{  /* 主方法,实现对本类的其它方法的调用 */  public final int calculate(String exp,String opt){    int array[]=split(exp,opt)    return calculate(array[0],array[1]);  }
/* 抽象方法,需要子类进行重写 */ abstract public int calculate(int num1,int num2); public int[] split(String exp,String opt){ String array[]=exp.split(opt); int arrayInt[]=new int[2]; arrayInt[0]=Integer.parseInt(array[0]); arrayInt[1]=Integer.parseInt(array[1]); return arrayInt; }}



- Pluspublic class Plus extends AbstractCalculator{ @Override public int calculate(int num1,int num2){ return num1+num2; }}



- StrategyTestpublic class StrategyTest{ public static void main(String[] args){ String exp="8+8"; AbstractCalculator cal=new Plus(); int result=cal.calculate(exp,"\\+"); System.out.println(result); }}
复制代码


Test 的执行过程:


  • 首先将 exp 和"\ \ +"做参数,调用 AbstractCalculator 类里的**calculate(String,String)**方法

  • calculate(String,String) 里调用同类的 split()

  • 然后再调用 calculate(int,int) 方法

  • 从这个方法进入到子类中

  • 执行完 return num1+num2 之后,将值返回到 AbstractCalculator 类,赋值给 result, 打印出来

观察者模式(Observer)

  • 观察者模式是类与类之间的关系,不涉及继承

  • 观察者模式类似邮件订阅和 RSS 订阅:

  • 当你订阅了该内容,如果后续有更新,会及时接收到通知

  • 观察者模式: 当一个对象变化时,依赖该对象的对象都会接收到通知,并且随着变化.对象之间是一对多的关系

  • MySubject 类是主对象

  • Observer1 Observer2 是依赖于 MySubject 的对象

  • MySubject 变化时 ,Observer1 Observer2 必然变化

  • AbstractSubject 类中定义者需要监控的对象列表,可以对这些对象进行修改:增加或者删除被监控对象

  • MySubject 变化时 ,AbstractSubject 类负责通知在列表内存在的对象


- Observerpublic interface Observer{  public void update();}



- Observer1public class Observer1 implements Observer{ @Override public void update(){ System.out.println("Observer1 has received!"); }}



- Observer2public class Observer2 implements Observer{ @Override public void update(){ System.out.println("Observer2 has received!"); }}



- Subjectpublic interface Subject{ /* 增加观察者 */ public void add(Observer observer);
/* 删除观察者 */ public void del(Observer observer);
/* 通知所有观察者 */ public void notifyObservers();
/* 自身的操作 */ public void operation();}



- AbstractSubjectpublic abstract class AbstractSubject implements Subject{ private Vector<Observer> vector=new Vector<Observer>(); @Override public void add(Observer observer){ vector.add(observer); } @Override public void del(Observer observer){ vector.remove(observer); }
@Override public void notifyObservers(){ Enumeration<Observer> enumo=vector.elements(); while(enumo.hasMoreElements()){ enumo.nextElement().update(); } }}



- MySubjectpublic class MySubject extends AbstractSubject{ @Override public void operation(){ System.out.println("update self!"); notifyObservers(); }}



- ObserverTestpublic class ObserverTest{ public static void main(String[] args){ Subject sub=new MySubject(); sub.add(new Observer1()); sub.add(new Observer2());
sub.operation(); }}
复制代码


  • 观察者模式根据关系图,新建项目,使用代码按照总体思路走一遍,这样容易理解观察者模式的思想

迭代子模式(Iterator)

  • 迭代子模式是类与类之间的关系,不涉及继承

  • 迭代子模式: 顺序访问聚集中的对象. 包含两层意思:

  • 聚集对象: 需要遍历的对象

  • 迭代器对象: 用于对聚集对象进行遍历访问

  • MyCollection 中定义了集合的一些操作

  • MyIterator 中定义了一系列迭代操作,并且持有 Collection 实例


- Collectionpublic interface Collection{  public Iterator iterator();
/* 取得集合元素 */ public Object get(int i);
/* 取得集合大小 */ public int size();}



- Iteratorpublic interface Iterator{ // 前移 puublic Object previous();
// 后移 public Object next(); public boolean hasNext();
// 取得第一个元素 public Object first(); }



- MyCollectionpublic class MyCollection implements Collection{ public String string[]={"A","B","C","D","E"};
@Override public Iterator iterator(){ return new MyIterator(this); }
@Override public Object get(int i){ return string[i]; }
@Override public int size(){ return string.length; }}



- MyIteratorpublic class MyIterator implements Iterator{ private Collection collection; private int pos=-1;
public MyIterator(Collection collection){ this.collection=collection; }
@Override pbulic Object previous(){ if(pos>0){ pos--; } return collection.get(pos); }
@Override public Object next(){ if(pos<collection.size()-1){ pos++; } return collection.get(pos); }
@Override public Object hasNext(){ if(pos<collection.size()-1){ return true; }else{ return false; } }
@Override public Object first(){ pos=0; return collection.get(pos); }

}



- Testpublic class Test{ Collection collection=new MyCollection(); Iterator it=collection.iterator();
whhile(it.hasNext()){ System.out.println(it.next()); }}
复制代码


  • JDK 中各个类都是这些基本的集合,加上一些设计模式,再加一些优化组合到一起的,只要掌握这些,可以写出自定义的集合类,甚至框架

责任链模式(Chain of Responsibility)

  • 类与类之间的关系,不涉及继承

  • 责任链模式:

  • 有多个对象,每个对象持有对下一个对象的引用,这样形成一条链,直到某个对象决定处理该请求

  • 请求发出者并不清楚到底最终哪个对象会处理该请求

  • 责任链模式可以实现 :在隐瞒客户端的情况下,对系统进行动态调整

  • Abstracthandler 类提供了 get set 方法,方便 MyHandler 类设置和修改引用对象

  • MyHandler 类是核心,实例化后生成一系列相互持有的对象,构成一条链


- Handlerpublic interface Handler{  public void operator();}



- AbstractHandlerpublic abstract class AbstractHandler{
private Handler handler;
private Handler getHandler(){ return handler; }
private void setHandler(Handler handler){ this.handler=handler; }}



- MyHandlerpublic class MyHandler extends AbstractHandler implements Handler{ private String name; public MyHandler(String name){ this.name=name; }
@Override public void operator(){ System.out.println(name+"deal!"); if(getHandler()!=null){ getHandler().operator(); } }}



- Testpublic class Test{ public static void main(String[] args){ MyHandler h1=new MyHandler("h1"); MyHanlder h2=new MyHandler("h2"); MyHandler h3=new MyHandler("h3"); h1.setHandler(h2); h2.setHandler(h3);
h1.operator(); }}
复制代码


  • 链接上的请求可以是一条链,可以是一个树,还可以是一个环

  • 模式本身不受这个约束,需要自定义实现

  • 在同一个时刻,命令只允许由一个对象传给另一个对象,不允许传给多个对象

命令模式(Command)

  • 类与类之间的关系,不涉及继承

  • 命令模式理解示例:

  • 司令员的作用是: 发出口令

  • 口令经过传递,传到士兵耳中,士兵去执行

  • 这个过程好在:司令,口令,士兵三者相互解藕

  • 任何一方都不用去依赖其它方,只需要做好自身的事即可

  • 司令员要的是结果,不会去关注士兵到底怎么实现的

  • Invoker 是调用者(司令员)

  • Receiver 是被调用者(士兵)

  • MyCommand 是命令,实现了 Command 接口,持有接收对象


- Commandpublic interface Command{  public void exe();}



- MyCommandpublic class MyCommand implements Command{ private Receiver receiver;
public MyCommand(Receiver receiver){ this.receiver=receiver; }
@Override public void exe(){ receiver.action(); }}



- Receiverpublic class Receiver{ public void action(){ System.out.println("Command Received!"); }}



- Invokerpublic class Invoker{ private Command command;
public Invoker(Command command){ this.command=command; }
public void action(){ command.exe(); }}



- Testpublic class Test{ public static void main(String[] args){ Receiver receiver=new Receiver(); Command cmd=new MyCommand(receiver); Invoker Invoker=new Invoker(cmd); invoker.action(); }}
复制代码


  • 命令模式的目的: 达到命令的发出者和执行者之间的解耦,实现请求和执行分开

  • Struts 其实就是一种将请求和呈现分离的技术,使用了命令模式的设计思想

备忘录模式(Memento)

  • 备忘录模式 :主要目的是保存一个对象的某个状态,以便在适当的时候恢复对象

  • 备忘录模式理解:

  • 假设有原始类 A,A 中有各种属性,A 可以决定需要备份的属性

  • 备忘录类 B 用来存储 A 的一些内部状态

  • 类 C 用来存储备忘录,并且只能存储,不能进行修改等操作

  • Original 类是原始类,里面有需要保存的属性 value 及创建一个备忘录类,用来保存 value

  • Memento 类是备忘录类

  • Storage 类是存储备忘录的类,持有 Memento 类的实例


- Originalpublic class Original{  private String value;
private String getValue(){ return value; }
private void setValue(String value){ this.value=value; }
public Original(String value){ this.value=value; }
public Memento createMemento(){ return new Memento(value); }
public void restoreMemento(Memento memento){ this.value=memento.getValue(); }}



- Mementopublic class Memento{ private String value;
public Memento(String value){ this.value=value; }
public String getValue(){ return value; }
public void setValue(String value){ this.value=value; }}



- Storagepublic class Storage{ private Memento memento;
public Storage(Memento memento){ this.memento=memento; }
public Memento getMemento(){ return memento; }
public void setMemento(Memento memento){ this.memento=memento; }}



- Testpublic class Test{ public static void main(String[] args){ // 创建原始类 Original original=new Original("egg");
// 创建备忘录 Storage storage=new Storage(original.createMemento());
// 修改原始类的状态 System.out.println("初始状态为:"+original.getValue()); original.setValue("bulk"); System.out.println("修改后的状态:"+original.getValue());
// 恢复原始类的状态 original.restoreMemento(storage.getMemento()); System.out.println("恢复后的状态为:"+original.getValue()); }}
复制代码


  • 新建原始类时 ,value 被初始化为 egg, 后经过修改,将 value 值修改为 bulk, 最后进行恢复状态,结果成功恢复

状态模式(State)

  • 状态模式 :当对象的状态改变时,同时改变对象的行为

  • 状态模式理解示例:

  • QQ 有几种不同的状态:在线,隐身,忙碌等

  • 每个状态对应不同的操作,而且好友也能看到相关的状态

  • 状态模式包括两层含义:

  • 可以通过改变状态来获得不同的行为

  • 对象状态的变化可以被发现

  • State 类是个状态类

  • Context 类可以实现切换


- Statepublic class State{  private String value;
private String getValue(){ return value; }
private void setValue(String value){ this.value=value; }
public void method1(){ System.out.println("Execute the first opt!"); }
public void method2(){ System.out.println("Execute the second opt!"); }}



- Contextpublic class Context{ private State state;
private Context(State state){ this.state=state; }
public State getState(){ return state; }
public void setState(){ this.state=state; }
public void method(){ if(state.getValue().equals("state1")){ state.method1(); }else if(state.getValue().equals("state2")){ state.method2(); } }}



- Testpublic class Test{ public static void main(String[] args){ State state=new State(); Context context=new Context(state);
// 设置第一种状态 state.setValue("state1"); context.method();
// 设置第二种状态 state.setValue("state2"); context.method(); }}
复制代码


  • 状态模式的应用场景十分广泛:在做网站的时候,希望根据对象的属性,区别一些功能等,比如说权限控制等等

访问者模式(Visitor)

  • 访问者模式将数据结构和作用于结构上的操作解耦,使得操作集合可以相对自由地进行演化

  • 访问者模式适用于数据结构相对稳定,算法容易变化的系统:

  • 访问者模式使得算法操作增加变得更加容易

  • 若系统数据结构对象易于变化,经常有新的对象增加进来,则不适合使用访问者模式

  • 访问者模式的特点:

  • 优点: 增加操作容易

  • 增加操作意味着增加新的访问者

  • 访问者模式将有关行为集中到一个访问者对象中, 这些行为的改变不影响系统数据结构

  • 缺点: 增加新的数据结构很困难

  • 访问者模式 :是一种分离对象数据结构和行为的方法,通过这种分离,可以达到为一个被访问者动态添加新的操作而无需做任何修改的效果

  • 一个 Visitor 类,存放要访问的对象

  • Subject 类中有 accept 方法,接收将要访问的对象 ,getSubject() 获取将要被访问的属性


- Visitorpublic interface Visitor{  public void visit(Subject sub);}



- MyVisitorpublic class MyVisitor implements Visitor{ @Override public void visit(Subject sub){ System.out.println("visit the subject:"+sub.getSubject()); }}



- Subjectpublic interface Subject{ public void accept(Visitor visitor); public String getSubject();}



- MySubjectpublic class MySubject implements Subject{ @Override public void accept(Visitor visitor){ visitor.visit(this); } @Override public String getSubject(){ return "love"; }}



- Testpublic class Test{ public static void main(String[] args){ Visitor visitor=new MyVisitor(); Subject sub=new MySubject(); sub.accept(visitor); }}
复制代码


  • 访客模式适用场景:

  • 如果要为一个现有的类增加新功能:

  • 新功能是否会与现有功能出现兼容性问题

  • 以后会不会还有新功能需要添加

  • 如果类不允许修改代码怎么处理

  • 这些问题最好的解决办法就是访客模式

  • 访问者模式适用于数据结构相对稳定的系统,将数据结构和算法解耦

中介者模式(Mediator)

  • 中介者模式是用来降低类与类之间的耦合的:

  • 类与类之间有依赖关系的话,不利于功能的拓展和维护

  • 因为只要修改一个对象,其它关联的对象都要进行修改

  • 中介者模式: 只需要关心 Mediator 类的关系,具体类与类之间的关系及调度交给 Mediator, 与 Spring 容器的作用类似

  • User 类统一接口

  • User1 User2 分别是不同的对象:

  • 二者之间有关联

  • 如果不采用中介者模式.则需要二者相互持有引用,这样二者的耦合度很高

  • 为了解耦,引入了 Mediator 类,提供统一接口

  • MyMediator 为实现类:

  • 持有 User1 User2 的实例,用来实现对 User1 User2 的控制

  • 这样 User1 User2 两个对象就可以相互独立,只需保持与 Mediator 之间的关系就可以

  • Mediator 类用来维护


- Mediatorpublic interface Mediator{  public void createMediator();
public void workAll();}



- MyMediatorpublic class MyMediator implements Mediator{ private User user1; private User user2;
public User getUser1(){ return user1; }
public User getUser2(){ return user2; }
@Override public void createMediator(){ user1=new User1(this); user2=new User2(this); }
@Override public void workAll(){ user1.work(); user2.work(); }}



- Userpublic abstract class User{ private Mediator mediator; public Mediator getMediator(){ return mediator; }
public User(Mediator mediator){ this.mediator=mediator; }
public abstract void work();}



- User1public class User1 extends User{ public User1(Mediator mediator){ super(mediator); }
@Override public void work(){ System.out.println("user1 exe!"); }}



- User2public User2 extends User{ public User2(Mediator mediator){ super(mediator); }
@Override public void work(){ System.out.println("user2 exe!"); }}



- Testpublic class Test{ public static void main(String[] args){ Mediator mediator=new MyMediator();
mediator.createMediator(); mediator.workAll(); }}
复制代码

解释器模式(Interpreter)

  • 解释器模式一般主要应用在 OOP 开发中的编译器开发中,适用面比较窄

  • Context 类是一个上下文环境类

  • Plus Minus 分别是计算的实现


- Expressionpublic interface Expression{  public int interpret(Context context);}



- Pluspublic class Plus implements Expression{ @Override public int interpret(Context context){ return context.getNum1()+context.getNum2(); }}



- Minuspublic class Minus implements Expression{ @Override public void interpret(Context context){ return context.getNum1()-context.getNum2(); }}



- Contextpublic class Context{ private int num1; private int num2;
public Context(int num1,int num2){ this.num1=num1; this.num2=num2; }
public int getNum1(){ return num1; }
public void setNum1(int num1){ this.num1=num1; }
public int getNum2(){ return num2; }
public void setNum2(int num2){ this.num2=num2; }}



- Testpublic class Test{ public static void main(String[] args){ // 计算 9+2-8 int result=new Minus().interpret((new Context(new Plus().interpret(new Context(9,2)),8))); System.out.println(result); }}
复制代码


  • 解释器模式是来用作各种各样的解释器 z

发布于: 3 小时前阅读数: 3
用户头像

一位攻城狮的自我修养 2021.04.06 加入

分享技术干货,面试题和攻城狮故事。 你的关注支持是我持续进步的最大动力! https://github.com/ChovaVea

评论

发布
暂无评论
Java中23种设计模式详解:详细分析11种行为型模式