电子商务毕业设计网站,易尔通做网站怎么样,手机电商网站 模板,网页设计素材源文件前言
现代社会#xff0c;技术日新月异#xff0c;要想跟上技术的更新就必须不断学习#xff0c;而学习技术最有效方式就是阅读优秀的源码#xff0c;而优秀的源码都不是简单的逻辑堆积#xff0c;而是有很灵活的设计模式应用其中#xff0c;如果我们不懂设计模式#…前言
现代社会技术日新月异要想跟上技术的更新就必须不断学习而学习技术最有效方式就是阅读优秀的源码而优秀的源码都不是简单的逻辑堆积而是有很灵活的设计模式应用其中如果我们不懂设计模式那么就难以读懂优秀的源码不能读懂源码就只能停留在低级的技术应用层面可以说不可能晋级为一名工程师。
而设计模式说到底是一种思维学习而思维的学习是最困难的如果你不能接受一种思维那么基于这种思维实现的功能和逻辑你怎么看怎么都觉得不对劲怎么都觉得无法理解。那么想要拥有一种思维最简单的方式就是反复“背诵”反复理解反复使用本文就是提供一篇便于你理解便于你反复“背诵”的文章文本将常见设计模式最核心的精华以及思想通过清晰的UML类图和代码示例展现出来只要你能反复理解反复“背诵”尝试使用相信你一定能够彻底将这种思维占为己有在编写代码时能够无意识的灵活运用各种设计模式编写优秀的代码。
这篇文章是我对《设计模式之禅》学习后基于个人理解所总结的常用设计模式的核心知识点如果时间充足想学习更详细的内容可以去学习作者原著。
学习本篇文章之前有两点建议
如果对UML类图不清晰的强烈建议先学习我的这篇关于UML的文章 快速读懂UML类图搞懂类之间的6大关系轻松绘制UML类图否则将很难理解本文。建议结合每种设计模式的示例代码进行学习各种设计模式的案例代码已上传至Gitee仓库链接如下https://gitee.com/mekeater/design-pattern
设计模式是一种思维绝不是一蹴而就的本文只能尽可能的帮助博友理解各种设计模式的思想如果想达到灵活应用还需要反复回顾反复理解反复应用我自己也是常常回来阅读的。
一、工厂方法模式
1. 定义
只需要定义一个具体工厂类类中包含创建对象的方法即可适用于只创建同一种等级的对象通用类图如下
2. 案例
女娲造不同肤色的人类采用工厂方法模式的类图如下 以上类图核心实现代码
public class HumanFactory extends AbstractHumanFactory{Overridepublic T extends IHuman T createHuman(ClassT c) {IHuman humannull;try {human (T)Class.forName(c.getName()).newInstance();}catch (Exception e){System.out.printf(e.toString());}return (T) human;}
}3. 扩展
3.1 静态工厂模式
其实对于女娲造不同肤色的人不需要抽象工厂类直接在具体的工厂类中放一个创建不同肤色人类的静态方法即可而这种在工厂类中通过静态方法创建对象的模式就称之为静态工厂模式。 女娲造不同肤色的人类采用静态工厂模式的类图如下
3.2 通过工厂方法模式代替单例模式
类图如下 类图中核心实现代码如下
public class SingletonFactory {private static Singleton singleton;static {try {Class? c1 Class.forName(Singleton.class.getName());Constructor? constructor c1.getDeclaredConstructor();constructor.setAccessible(true);singleton (Singleton) constructor.newInstance();} catch (Exception e){}}public Singleton getSingleton(){return singleton;}
}3.3 工厂方法模式升级为抽象工厂模式
先预热一下抽象工厂模式将女娲造不同肤色的人的一个工厂抽象为多个工厂类图如下
二、抽象工厂模式
1. 定义
抽象工厂模式是工厂方法模式的升级适用于创建包含多个不同等级对象且每个对象又有多个产品族组成这种对象的创建。 如汽车有奥迪宝马等不同的品牌而每个汽车又包含左车门和右车门等产品族。那么这种汽车对象就适合用抽象工厂模式。
抽象工厂模式有多个具体的工厂实现类。
抽象工厂模式通用类图如下
2. 案例
女娲要造不同肤色不同性别的人类采用抽象工厂模式的类图如下 工厂代码如下
public class FemaleFactory implements IHumanFactory{Overridepublic IHuman createBlackHuman() {return new FemaleBlackHuman();}Overridepublic IHuman createYellowHuman() {return new FemaleYellowHuman();}Overridepublic IHuman createWhiteHuman() {return new FemaleWhiteHuman();}
}public class MaleFactory implements IHumanFactory{Overridepublic IHuman createBlackHuman() {return new MaleBlackHuman();}Overridepublic IHuman createYellowHuman() {return new MaleYellowHuman();}Overridepublic IHuman createWhiteHuman() {return new MaleWhiteHuman();}
}三、模板方法模式
1. 定义
所谓模板方法模式就是在抽象父类中就定义一个模板方法该方法控制其它方法的流程而其它方法由子类实现。适用于对象要按照一定的规则和顺序调用基本方法。
抽象类定义了部分抽象方法由子类实现子类执行的结果影响了父类的结果也就是子类对父类产生了影响这在复杂的项目中会带来代码阅读的难度而且也会让新手产生不适感。
模板方法模式通用类图如下
2. 案例
构建不同类型的奥迪车基于模板方法模式进行设计的类图如下 核心实现代码如下
public abstract class AbstractAoDiCar {protected abstract void start();protected abstract void stop();protected abstract void alarm();protected abstract void enginBoom();//模板方法public void run(){this.start();this.enginBoom();this.alarm();this.stop();}
}3. 扩展钩子方法
就是子类对一个方法的操作会导致父类中模板方法的执行受到影响这样的方法就称为钩子方法。
如我们要让AoDiCarModel1能够按喇叭而AoDiCarModel2不能按喇叭那该如何做呢这个时候我们只需要添加一个钩子方法即可类图如下
public abstract class AbstractAoDiCar {protected abstract void start();protected abstract void stop();protected abstract void alarm();protected abstract void enginBoom();protected boolean isAlarm(){return true;}//模板方法public void run(){this.start();this.enginBoom();if (isAlarm()){this.alarm();}this.stop();}
}public class AoDiCarModel1 extends AbstractAoDiCar{private boolean alarmFlag true; //要响喇叭Overrideprotected void start() {System.out.println(奥迪model1启动);}Overrideprotected void stop() {System.out.println(奥迪model1停止);}Overrideprotected void alarm() {System.out.println(奥迪model1喇叭响);}Overrideprotected void enginBoom() {System.out.println(奥迪model1引擎发动);}Overrideprotected boolean isAlarm() {return this.alarmFlag;}public void setAlarm(boolean isAlarm)//钩子方法{this.alarmFlagisAlarm;}
}四、建造者模式
1. 定义
建造者模式是将一个复杂对象的构建和它的表示分离使得同样的构建过程可以创建不同的表示。适用于相同的方法不同的执行顺序产生不同的事件结果这种对象的构建。
建造者模式通用类图如下 Product采用模板方法模式构建然后重点将模板方法通过构建者进行控制同时通过Director类避免高层模块深入到建造者内部的实现类。
2. 案例
构建不同启动操作和顺序的宝马以及奔驰汽车对象。 核心代码如下
public abstract class AbsCarModel {protected ArrayListString sequence;protected abstract void start();protected abstract void stop();protected abstract void alarm();protected abstract void enginBoom();final public void run() {for (String s : sequence) {if (s.equals(start)) {start();} else if (s.equals(stop)) {stop();} else if (s.equals(alarm)) {alarm();} else if (s.equals(enginBoom)) {enginBoom();}}}final public void setSequence(ArrayListString sequence){this.sequencesequence;}
}public class BMBuilder extends AbsCarBuilder{BMModel bmModelnew BMModel();Overridepublic void setSequence(ArrayList sequence) {this.bmModel.sequencesequence;}Overridepublic AbsCarModel getCarModel() {return this.bmModel;}
}public class Director {private ArrayListString sequencenew ArrayList();private BMBuilder bmBuildernew BMBuilder();private BenzBuilder benzBuildernew BenzBuilder();public AbsCarModel getABenzModel(){this.sequence.clear();//奔驰A型操作步骤this.sequence.add(start);this.sequence.add(stop);benzBuilder.setSequence(this.sequence);return benzBuilder.getCarModel();}public AbsCarModel getBBenzModel(){this.sequence.clear();//奔驰B型操作步骤this.sequence.add(enginBoom);this.sequence.add(start);this.sequence.add(stop);benzBuilder.setSequence(this.sequence);return benzBuilder.getCarModel();}public AbsCarModel getABMModel(){this.sequence.clear();//宝马A型操作步骤this.sequence.add(alarm);this.sequence.add(start);this.sequence.add(stop);bmBuilder.setSequence(this.sequence);return bmBuilder.getCarModel();}public AbsCarModel getBBMModel(){this.sequence.clear();//宝马B型操作步骤this.sequence.add(start);bmBuilder.setSequence(this.sequence);return bmBuilder.getCarModel();}
}public class Client {public static void main(String[] args) {Director director new Director();//宝马A型车director.getABMModel().run();//奔驰B型车director.getBBenzModel().run();}
}Note: 建造者模式和工厂方法模式的区别 建造者模式最主要的功能是基本方法的调用顺序安排也就是这些基本方法已经实现了通俗地说就是零件的装配顺序不同产生的对象也不同;而工厂方法模式则重点是创建创建零件是它的主要职责组装顺序则不是它关心的。
五、代理模式
1. 定义
为其它对象提供一种代理以控制对这个对象的访问。适用于对象本身使用之前或者之后有很多细碎的需要要处理而这些细碎的需要交给代理去做就可以保证对象本身只处理实际的核心业务不用关心其它非本职责的任务。代理模式通用UML类图如下所示
2. 案例
如你一个游戏用户不要自己打怪升级那太累了想直接拿到高级别的ID进行高端游戏该用户就可以采用代理模式找一个代理用户帮自己升级UML类图如下 核心代码如下
//游戏代理用户
public class GamePlayerProxy implements IGamePlayer{//被代理用户private IGamePlayer gamePlayer;public GamePlayerProxy(IGamePlayer gamePlayer){this.gamePlayergamePlayer;}Overridepublic void login(String user, String psw) {this.gamePlayer.login(user,psw);}Overridepublic void killBoss() {this.gamePlayer.killBoss();}Overridepublic void upgrade() {this.gamePlayer.upgrade();}
}3. 扩展
3.1 普通代理
普通代理就是我们要知道代理的存在只有通过代理才能执行被代理对象的方法它要求客户端只能访问代理角色而不能访问真实角色。 采用普通代理对案例进行设计UML类图如下只是修改了真实角色和代理角色的构造函数这样就使得调用者只知道代理的存在但不用知道代理的真正角色是谁。 核心实现代码如下
//游戏用户
public class GamePlayer implements IGamePlayer {private String name;public GamePlayer(IGamePlayer proxy, String name) throws Exception {if (proxy null) {throw new Exception(未传入代理对象不能创建真实角色);} else {this.name name;}}Overridepublic void login(String user, String psw) {System.out.println(登录名 user 密码 psw 登录成功);}Overridepublic void killBoss() {System.out.println(this.name 在打怪);}Overridepublic void upgrade() {System.out.println(this.name 升级了);}
}//游戏代理用户
public class GamePlayerProxy implements 代理模式.IGamePlayer {//被代理用户private IGamePlayer gamePlayer;public GamePlayerProxy(String name) throws Exception {this.gamePlayer new GamePlayer(this, name);}Overridepublic void login(String user, String psw) {this.gamePlayer.login(user, psw);}Overridepublic void killBoss() {this.gamePlayer.killBoss();}Overridepublic void upgrade() {this.gamePlayer.upgrade();}
}public class Client {public static void main(String[] args) throws Exception {//调用者只知道代理的存在不用知道代理的真实对象是谁GamePlayerProxy gamePlayerProxy new GamePlayerProxy(张三);gamePlayerProxy.login(zhangsan,123);gamePlayerProxy.killBoss();gamePlayerProxy.upgrade();}
}
3.2 强制代理
强制代理是调用者直接调用真实角色而不必知道代理的存在因为真实角色管理代理角色。这就类似你看到一个明星想问她的一些事情但她却让你找她的助理这里面明星就是真实角色而助理就是代理角色你虽然直接看到明星但得到的结果却是助理。 采用强制代理对案例进行设计的UML类图如下 核心实现代码如下
//游戏用户
public class GamePlayer implements IGamePlayer {private IGamePlayer proxy null;private String name;public GamePlayer(String name) {this.name name;}Overridepublic void login(String user, String psw) {if (isProxy()) {System.out.println(登录名 user 密码 psw 登录成功);} else {System.out.println(请使用指定的代理访问);}}Overridepublic void killBoss() {if (isProxy()) {System.out.println(this.name 在打怪);} else {System.out.println(请使用指定的代理访问);}}Overridepublic void upgrade() {if (isProxy()) {System.out.println(this.name 升级了);} else {System.out.println(请使用指定的代理访问);}}Overridepublic IGamePlayer getProxy() {this.proxy new GamePlayerProxy(this);return this.proxy;}private boolean isProxy() {if (this.proxy null) {return false;} else {return true;}}
}//游戏代理用户
public class GamePlayerProxy implements IGamePlayer {//被代理用户private IGamePlayer gamePlayer;public GamePlayerProxy(IGamePlayer gamePlayer){this.gamePlayergamePlayer;}Overridepublic void login(String user, String psw) {this.gamePlayer.login(user,psw);}Overridepublic void killBoss() {this.gamePlayer.killBoss();}Overridepublic void upgrade() {this.gamePlayer.upgrade();}//代理的代理暂时还没有就是自己Overridepublic IGamePlayer getProxy() {return this;}
}客户端使用强制代理
public class Client {public static void main(String[] args) throws Exception {//真实角色自己操作不行GamePlayer gamePlayernew GamePlayer(张三);gamePlayer.login(zhangsan,123);gamePlayer.killBoss();gamePlayer.upgrade();System.out.println();//创建一个代理操作真实角色也不行GamePlayerProxy proxy new GamePlayerProxy(gamePlayer);proxy.login(zhangsan,123);proxy.killBoss();proxy.upgrade();System.out.println();//必须由真实角色获得代理对象才能对真实角色进行操作IGamePlayer proxy1 gamePlayer.getProxy();proxy1.login(zhangsan,123);proxy1.killBoss();proxy1.upgrade();}
}3.3 代理的真正意义
如果代理仅仅是调用真实角色的方法那直接用真实角色即可再加个代理有啥用因为代理不仅仅会调用真实角色的方法往往需要自己先/后处理一些琐碎的事务之后才能调用真实角色的方法。
也就是说代理类不仅仅可以实现主题接口也可以实现其他接口完成不同的任务而且代理的目的是在目标对象方法的基础上作增强这种增强的本质通常就是对目标对象的方法进行拦截和过滤。
如游戏代打案例代理帮你升级肯定不会免费吧一定会收费的因此正常一点的游戏代打UML类图如下所示 核心代码如下
//游戏代理用户
public class GamePlayerProxy implements IGamePlayer, IProxy {//被代理用户private IGamePlayer gamePlayer;public GamePlayerProxy(IGamePlayer gamePlayer){this.gamePlayergamePlayer;}Overridepublic void login(String user, String psw) {this.gamePlayer.login(user,psw);}Overridepublic void killBoss() {this.gamePlayer.killBoss();}Overridepublic void upgrade() {this.gamePlayer.upgrade();this.pay();}Overridepublic void pay() {System.out.println(代理费100元);}
}3.4 动态代理
动态代理核心技术是反射因此在理解这种设计模式之前强烈建议先看下我的这篇关于“反射”的文章 彻底玩转Java注解和反射。
动态代理是在实现阶段不用关心代理谁而是在运行阶段才指定代理哪一个对象。现在流行的面向横切编程AOP其核心就是采用了动态代理机制。
基于java.lang.reflect包下的InvocationHandler接口和Proxy类采用动态代理模式对案例进行实现的UML类图如下 核心实现代码如下
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class GamePlayerIH implements InvocationHandler {//被代理的实例Object obj null;GamePlayerIH(Object obj) {this.obj obj;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//通过反射调用被代理对象方法Object result method.invoke(this.obj, args);return result;}
}public class Client {public static void main(String[] args) {IGamePlayer gamePlayernew GamePlayer(张三);GamePlayerIH gamePlayerIHnew GamePlayerIH(gamePlayer);ClassLoader classLoader gamePlayer.getClass().getClassLoader();//动态产生一个代理者(宣称所有接口方法都已通过InvocationHandle实现)IGamePlayer proxy (IGamePlayer) Proxy.newProxyInstance(classLoader, gamePlayer.getClass().getInterfaces(), gamePlayerIH);proxy.login(zhangsan,123);proxy.killBoss();proxy.upgrade();}
}如果我们想在调用代理对象的某个方法之前或者之后通知一条消息或者执行什么操作该如何做呢很简单例如我们想要在执行login方法的时候发出一条消息只需要对GamePlayerIH 做如下修改即可这种通知方式就是AOP思想核心。
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;public class GamePlayerIH implements InvocationHandler {//被代理的实例Object obj null;GamePlayerIH(Object obj) {this.obj obj;}Overridepublic Object invoke(Object proxy, Method method, Object[] args) throws Throwable {//通过反射调用被代理对象方法Object result method.invoke(this.obj, args);//AOP横切在程序运行中间添加一个通知消息if (method.getName().equals(login)) {System.out.println(通知有人用你的账号登录了游戏);}return result;}
}动态代理通用UML类图如下DynamicProxy有两条线一条线去操作代理对象的任务另一条线是处理自己的通知。并且DynamicProxy类只是对Proxy.newProxyInstance方法的再封装而已让它形式上有一个代理类同时可以将自己的通知封装进去。 核心实现代码
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Proxy;public class DynamicProxyT {public static T T newProxyInstance(ClassLoader loader,Class?[] interfaces,InvocationHandler h){//寻找JoinPoint连接点,发出自己的通知new BeforeAdvice().exec();//生成动态代理return (T)Proxy.newProxyInstance(loader,interfaces,h);}
}静态代理和动态代理有什么区别? 都是需要实现一个代理类有区别注意看父类动态代理的主要意图就是解决我们常说的“审计”问题也就是横切面编程在不改变我们已有代码结构的情况下增强或控制对象的行为。
六、原型模式
1. 定义
原型模式就是先产生一个包含大量共有信息的类然后通过实现Object的clone方法拷贝出副本然后对副本修改部分细节信息就构建了一个完整的个性对象。 简单来说就是一个类实现Cloneable标记接口然后实现Object的clone方法然后就可以通过clone复制出另一个对象。Object类的clone方法的原理是从内存中具体地说就是堆内存 以二进制流的方式进行拷贝 重新分配一个内存块。 原型模式通用UML类图如下 核心代码如下
public class ConcretePrototype implements Cloneable{Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}
}2. 案例
如一份广告邮件内容基本相同我们可以就创建一个对象然后每次拷贝一份对象对其细节修改后就是一个全新的对象然后发出去。UML类图如下 核心实现代码如下
public class Mail implements Cloneable{private String receiver;private String subject;private String appellation;private String context;private String tail;public Mail(AdvTemplate advTemplate){this.subjectadvTemplate.getAdvSubject();this.contextadvTemplate.getAdvContext();}Overrideprotected Object clone() {try {return super.clone();} catch (CloneNotSupportedException e) {throw new RuntimeException(e);}}
}注意
拷贝有深拷贝和浅拷贝两种方式具体区别以及实现方法可以参考我的这篇文章若对象被final修饰则不能clone
七、中介者模式
1. 定义
用一个中介对象封装一系列相互关联对象的交互中介者使得各个对象直接不需要显示的相互作用降低各个对象直接的耦合性。适用于有一大堆相互关联的对象此时构造一个中介者来处理各个对象直接复杂的交互每个对象只需要通过中介者进行相应的操作即可。
类似在公司中有大量的员工每个员工与大量的同事之间在业务上都有一定的相互联系这时候就需要一个中介者来统一处理各个同事之间的业务联系。
中介者模式通用UML类图如下。ConcreteMediator是具体的中介者Colleague1Colleague2,…就是具有相互联系各个同事。
2. 案例
如我们需要设计一个软件管理公司对电脑的采购销售库存最直接的设计UML类图如下 核心实现代码如下
public class Purchase {public void buyComputer(int num){Stock stock new Stock();Sale sale new Sale();int saleScore sale.getSaleScore();if (saleScore80){System.out.println(销售良好采购电脑:num台);stock.increase(num);}else {System.out.println(销售不好采购电脑:num/2台);stock.increase(num/2);}}public void refuseBuy(){System.out.println(拒绝采购);}
}public class Sale {public void sellComputer(int num){Stock stock new Stock();Purchase purchase new Purchase();if (stock.getStockNum()num){System.out.println(库存不足采购num台);purchase.buyComputer(num);stock.increase(num);}System.out.println(销售电脑num台);stock.decrease(num);}public int getSaleScore(){Random random new Random(System.currentTimeMillis());int saleScore random.nextInt(100);System.out.println(销售情况得分saleScore);return saleScore;}public void discountSale(){Stock stock new Stock();System.out.println(打折销售清空库存stock.getStockNum());stock.decrease(stock.getStockNum());}
}public class Stock {private static int COMPUTER_NUMBER100;//初始100台public void increase(int num){COMPUTER_NUMBERnum;System.out.println(当前库存COMPUTER_NUMBER);}public void decrease(int num){COMPUTER_NUMBER-num;System.out.println(当前库存COMPUTER_NUMBER);}public int getStockNum(){return COMPUTER_NUMBER;}public void clearStock(){Purchase purchase new Purchase();Sale sale new Sale();System.out.println(库存压力大需要清库数量COMPUTER_NUMBER);sale.discountSale();purchase.refuseBuy();}
}三个类之间相互交互内部会有复杂的交互逻辑各个类的耦合性很高简单的三个对象还好但如果更多呢比如下图你还敢按照上面的写吗或者你真的写了估计写不到一半自己就想si了。 对于这么一堆有相互关联的对象就适用中介者模式来设计对于本案例采用中介者模式设计的UML类图如下 实现代码如下
public abstract class AbsMediator {protected Sale sale;protected Purchase purchase;protected Stock stock;public AbsMediator(){salenew Sale(this);purchasenew Purchase(this);stocknew Stock(this);}public abstract void execute(String tag, Object... objects);}public class Mediator extends AbsMediator{Overridepublic void execute(String tag, Object... objects) {if (tag.equals(0))//采购{this.buyComputer((Integer) objects[0]);} else if (tag.equals(1))//销售{this.sellComputer((Integer) objects[0]);} else if (tag.equals(2))//打折销售{this.discountSale();} else if (tag.equals(3))//清仓{this.clearStock();}}private void buyComputer(int num){int saleScore super.sale.getSaleScore();if (saleScore80){System.out.println(销售良好采购电脑:num台);super.stock.increase(num);}else {System.out.println(销售不好采购电脑:num/2台);super.stock.increase(num/2);}}private void sellComputer(int num){if (super.stock.getStockNum()num){System.out.println(库存不足采购num台);super.purchase.buyComputer(num);super.stock.increase(num);}System.out.println(销售电脑num台);super.stock.decrease(num);}private void discountSale(){System.out.println(打折销售清空库存super.stock.getStockNum());super.stock.decrease(super.stock.getStockNum());}private void clearStock(){System.out.println(库存压力大需要清库数量super.stock.getStockNum());super.sale.discountSale();super.purchase.refuseBuy();}
}public class Purchase extends AbsColleague{public Purchase(AbsMediator mediator) {super(mediator);}public void buyComputer(int num){super.mediator.execute(0,num);}public void refuseBuy(){System.out.println(拒绝采购);}
}public class Sale extends AbsColleague{public Sale(AbsMediator mediator) {super(mediator);}public void sellComputer(int num){super.mediator.execute(1,num);}public int getSaleScore(){Random random new Random(System.currentTimeMillis());int saleScore random.nextInt(100);System.out.println(销售情况得分saleScore);return saleScore;}public void discountSale(){super.mediator.execute(2);}
}public class Stock extends AbsColleague{private static int COMPUTER_NUMBER100;//初始100台public Stock(AbsMediator mediator) {super(mediator);}public void increase(int num){COMPUTER_NUMBERnum;System.out.println(当前库存COMPUTER_NUMBER);}public void decrease(int num){COMPUTER_NUMBER-num;System.out.println(当前库存COMPUTER_NUMBER);}public int getStockNum(){return COMPUTER_NUMBER;}public void clearStock(){super.mediator.execute(3);}
}note
中介者模式的缺点很明显那就是中介者会膨胀的很大而且逻辑很复杂同事类越多逻辑越复杂。面向对象的编程中对象之间必然有联系但并不是只要有联系就加入中介者因为本来简单的对象之间的联系不必用中介者模式但你非要用就会导致逻辑很复杂所以只有大量对象之间具有高度耦合的情况下再使用中介者模式。
八、命令模式
1. 定义
命令模式是将一个任务请求对应封装为一个命令对象并增加一个调用者来执行来接收和执行命令适用于任何带有命令情景的任务。具体来说适用于一个任务需要命令很多的对象去处理。命令模式通用UML类图如下封装一系列具体的命令对象ConcreteCommand然后由Invoker调用客户端只和Invoker交互。
2. 案例
如客户要求我们为其研发一个内部员工管理系统针对该任务我们安排了需求组美工组代码组三个小组合作完成该任务。
如果不采用命令模式UML类图如下客户端需要与各个组进行交互。 采用命令模式设置的UML类图如下 核心实现代码如下
public abstract class AbsCommand {protected RequirementGroup rgnew RequirementGroup();protected PageGroup pgnew PageGroup();protected CodeGroup cgnew CodeGroup();public abstract void execute();
}public class AddRequirementCommand extends AbsCommand{Overridepublic void execute() {super.rg.find();super.rg.add();super.rg.plan();}
}public class Invoker {private AbsCommand command;public void setCommand(AbsCommand command){this.commandcommand;}public void action(){this.command.execute();}
}public class Client {public static void main(String[] args) {//定义接头人Invoker invoker new Invoker();//封装命令AddRequirementCommand addRequirementCommand new AddRequirementCommand();//接收命令invoker.setCommand(addRequirementCommand);//执行命令invoker.action();}
}命令模式的优点是可以很好使得类之间进行解耦缺点也很明显有多少命令就有多少具体的命令对象子类数量将膨胀的非常大。
note中介者模式中的中介者是处理大量有依赖关系对象之间的操作而命令模式中的Invoker是接收封装的命令。
九、责任链模式
1. 定义
责任链模式适用于对于一个请求有一串对象可能去处理它即如果当前对象不能处理承担这个处理这个请求的责任则转给下一个对象去处理循环往复直至有对象处理为止。责任链的实现本质就是自定义单向链表类核心就是定义一个next。 责任链模式通用UML类图如下
2. 案例
古代对女性要求三从四德三从指的是一个女子若未出嫁则要听从父亲的话若出嫁则要听从丈夫的话若夫亡则要听从儿子的话。这个场景中有三个对象可能处理女子的请求完全适合用责任链模式来设计UML类图如下 核心实现代码如下
public interface IWomen {int getType();String getRequest();
}public abstract class AbsHandle {public final static int FATHER_TYPE_REQUEST1;public final static int HUSBAND_TYPE_REQUEST2;public final static int SON_TYPE_REQUEST3;private int type;private AbsHandle nextHandle;public AbsHandle(int type){this.typetype;}public final void HandleMessage(IWomen women){if (women.getType()this.type){this.response(women);}else{if (this.nextHandle !null){this.nextHandle.HandleMessage(women);}else {System.out.println(无人负责故无所约束你决定\n);}}}public void setNext(AbsHandle handle){this.nextHandle handle;}protected abstract void response(IWomen women);
}public class Father extends AbsHandle{public Father() {super(FATHER_TYPE_REQUEST);}Overrideprotected void response(IWomen women) {System.out.println(女儿向父亲请示);System.out.println(women.getRequest());System.out.println(父亲答复同意\n);}
}public class Client {public static void main(String[] args) {Random random new Random();ListIWomen womenListnew ArrayList();for (int i 0; i 5; i) {womenList.add(new Women(random.nextInt(4),我要出去逛逛));}AbsHandle fathernew Father();AbsHandle husbandnew Husband();AbsHandle sonnew Son();father.setNext(husband);husband.setNext(son);for (IWomen iWomen : womenList) {father.HandleMessage(iWomen);}}
}十、观察者模式
1. 定义
观察者模式是定义对象之间一种一对多的依赖关系使得每当一个对象被观察者Observable改变状态则所有依赖于它的对象观察者Observer都会得到通知并被自动更新。观察者模式的核心实现是将观察者安插到被观察者内部被观察者一有动静就会通知给观察者。观察者模式的通用UML类图如下
2. 案例
所谓知己知彼百战百胜古代如何知道敌人的信息呢你想的没错通过安排间谍那么通过观察者模式实现该方案敌方就是被观察者而间谍就是观察者如李斯王斯…想要观察韩非子的一举一动基于观察者模式UML类图如下 核心实现代码如下
public class HanFeiZi implements IHanFeiZi,IObservable{private ListIObserver observersnew ArrayList();Overridepublic void haveBreakfast() {System.out.println(韩非子老子要吃饭了);this.notifyObserver(韩非子在吃饭);}Overridepublic void haveFun() {System.out.println(韩非子老子要玩耍了);this.notifyObserver(韩非子在玩耍);}Overridepublic void addObserver(IObserver observer) {observers.add(observer);}Overridepublic void deleteObserver(IObserver observer) {observers.remove(observer);}Overridepublic void notifyObserver(String context) {for (IObserver observer : observers) {observer.update(context);}}
}public class LiSi implements IObserver{Overridepublic void update(String context) {System.out.println(李斯观察到韩非子有活动);System.out.println(李斯秦老板context);}
}public class Client {public static void main(String[] args) {HanFeiZi hanFeiZi new HanFeiZi();LiSi liSi new LiSi();WangSi wangSi new WangSi();hanFeiZi.addObserver(liSi);hanFeiZi.addObserver(wangSi);hanFeiZi.haveFun();}
}Note: Java本身提供了观察者模式的被观察者模板对象java.util.Observable以及观察者的模板对象java.util.Observer我们可以直接用子类继承而不用自己再定义观察者和被观察者的接口类。但这种简单的观察者模式已经被取代可以在java.util.Observable中查看具体替代的原因及新的替代者。
十一、策略模式
1. 定义
策略模式是定义一组算法并将这些算法用高层类封装起来使得各个算法可以互相切换。适用于多个类只有在算法或者行为上稍有不同的场景。最直观的优点策略模式可以避免使用多重条件判断非常容易扩展。 策略模式非常简单可以说就是纯对面向对象的继承和多态机制的运用通用UML类图如下定义一个算法接口实现一组算法然后将算法接口聚合到高层类Context中。
2. 案例1
比如周瑜赔了夫人又折兵的故事中诸葛亮给了周瑜三个锦囊让他在不同的情况下依次打开应对当时遇到的情况这就是典型的策略问题何种情况应该采用何种策略采用策略模式的UML类图如下
public interface IStrategy {void operate();
}public class Context {IStrategy strategy;public Context(IStrategy strategy){this.strategystrategy;}void operate(){this.strategy.operate();}
}public class ZhaoYun_Client {public static void main(String[] args) {Strategy1 strategy1 new Strategy1();Context context new Context(strategy1);context.operate();contextnew Context(new Strategy2());context.operate();contextnew Context(new Strategy3());context.operate();}
}3. 案例2
采用常规策略模式实现加减算法UML类图如下 核心实现代码如下
public interface ICalculator {public int exec(int a,int b);
}public class Context {private ICalculator calculator;public Context(ICalculator calculator){this.calculatorcalculator;}public int exec(int a,int b){return this.calculator.exec(a,b);}
}public class Client {public static void main(String[] args) {int exec new Context(new Add()).exec(1, 5);System.out.println(exec);}
}
上面常规的策略模式也可以改为采用枚举实现策略枚举方式实现的代码可读性更好核心代码如下
public enum Calculator {ADD(){Overridepublic int exec(int a, int b) {return ab;}},SUB(-){Overridepublic int exec(int a, int b) {return a-b;}};private String value;//关键点枚举构造函数private Calculator(String _value){this.value_value;}public String getValue() {return value;}public abstract int exec(int a,int b);
}public class Client {public static void main(String[] args) {//可以看到枚举策略的可读性很好System.out.println(Calculator.ADD.exec(1,5));System.out.println(Calculator.ADD.getValue());}
}从上面的实现可以看出枚举固有的特性隐含的实现了策略模式的架构。
十二、装饰模式
1. 定义
装饰模式是动态的给一个对象添加一些额外的职责。适用于动态给一个对象附加或者撤销一些功能。装饰模式本质是继承关系的一个替代方案因为一层层继承是静态的扩展不具有动态性不易维护。 note装饰模式不要装饰太多层因为虽然可以方便增加装饰但装饰的层太多就像剥洋葱出现bug要剥很多次层才能找到问题增加系统的复杂度。 装饰模式通用UML类图如下:核心点在于装饰抽象类继承了抽象组件且抽象组件又聚合到了抽象装饰类。
2. 案例
比如你的成绩单如果只是看成绩每科分数确实不太理想但如果加上每科的最高成绩就会发现你的成绩与最高分其实没差多少说明是大家考的都不好或者再加上你的班级排名发现排名其实还进步了呢这样家长也许就能接受了你就少了一顿鸡毛掸子哈哈哈就这个场景采用装饰模式设计的UML类图如下 核心实现代码如下
public abstract class ASchoolReport {public abstract void report();public abstract void sign(String name);
}public abstract class ADecorator extends ASchoolReport {private ASchoolReport schoolReport;public ADecorator(ASchoolReport schoolReport){this.schoolReportschoolReport;}Overridepublic void report() {this.schoolReport.report();}Overridepublic void sign(String name) {this.schoolReport.sign(name);}
}public class HighScoreDecorator extends ADecorator{public HighScoreDecorator(ASchoolReport schoolReport) {super(schoolReport);}public void reportHighScore(){System.out.println(这次考试全班最高分语文75数学78自然80);}Overridepublic void report() {//装饰一下this.reportHighScore();super.report();}
}public class Father {public static void main(String[] args) {//原装成绩单ASchoolReport schoolReportnew YourSchoolReport();//装饰包装下最高分schoolReportnew HighScoreDecorator(schoolReport);//继续装饰包装下最排名schoolReportnew SortDecorator(schoolReport);//再把装饰好的成绩单拿给老爸看schoolReport.report();schoolReport.sign(老子);}
}十三、适配器模式
1. 定义
适配器模式适用于后期扩展功能时所提供的接口与系统现有接口不一致的情况通过适配器类将一个对象转换为客户端所需要的对象。使得原本因接口不匹配而无法一起工作的两个类可以一起工作。
适配器模式根据适配器类与被适配对象的关系又分为类适配器模式和对象适配器模式。如果适配器类继承于被适配对象就能完成适配这种模式称之为类适配器模式。但如若被适配对象不止一个的时候由于Java只能继承一个类因此需要通过将被适配对象聚合到适配器类中的方式实现适配这种模式称为对象适配器模式。
类适配器模式的通用UML类图如下 对象适配器模式的通用UML类图如下
2. 案例
比如一个系统的人员信息接口是IUsetInfo但是后期来了一个新业务用的人员信息数据接口是IOuterUser这两个接口是不一样的因此可以采用适配器模式实现两个接口的转换因为被适配的对象只有一个因此采用类适配器模式即可具体UML类图如下 核心实现代码如下
public interface IUserInfo {String getName();String getAge();String getAddress();String getJobPosition();
}public interface IOuterUser {Map getUserBaseInfo();Map getUerOfficeInfo();Map getUserHomeInfo();
}public class OuterAdapter extends OuterUser implements IUserInfo{Overridepublic String getName() {String name (String) super.getUserBaseInfo().get(name);System.out.println(name);return null;}Overridepublic String getAge() {String age (String) super.getUerOfficeInfo().get(age);System.out.println(age);return null;}Overridepublic String getAddress() {String address (String) super.getUserHomeInfo().get(address);System.out.println(address);return null;}Overridepublic String getJobPosition() {String jobPosition (String) super.getUerOfficeInfo().get(JobPosition);System.out.println(jobPosition);return null;}
}public class Client {public static void main(String[] args) {UserInfo userInfo new UserInfo();userInfo.getAddress();OuterAdapter outerAdapter new OuterAdapter();outerAdapter.getAddress();}
}十四、迭代器模式
1. 定义
迭代器模式提供一种方法访问一个容器对象中的各个元素而又不需要暴露对象的内部细节。其实就是实现Java.util.Iterator接口。因为Java对于常用容器都实现了Iterable接口所以像Java这种高级语言很少再自己使用迭代器模式因为它太常用了已经渗透到所有语言中不要开发者再去扩展。
2. 案例
比如一个Product集合采用迭代器模式实现对该集合的所有元素进行访问的UML类图如下
public interface IProject {String getProductInfo();void add(String name, int num, int cost);IProjectIterator iterator();
}public interface IProjectIterator extends Iterator {}public class ProjectIterator implements IProjectIterator{private ArrayListIProject projects;private int currItemIndex 0;public ProjectIterator(ArrayListIProject projects) {this.projects projects;}Overridepublic boolean hasNext() {if (this.currItemIndex projects.size() || this.projects.get(this.currItemIndex) null) {return false;} else {return true;}}Overridepublic IProject next() {return this.projects.get(this.currItemIndex);}
}public class Project implements IProject {private ArrayListIProject projects new ArrayList();private String name;private int num;private int cost;public Project() {}public Project(String name, int num, int cost) {this.name name;this.num num;this.cost cost;}Overridepublic String getProductInfo() {return 项目名称 this.name 项目人数 this.num 项目费用 this.cost;}Overridepublic void add(String name, int num, int cost) {this.projects.add(new Project(name, num, cost));}Overridepublic IProjectIterator iterator() {return new ProjectIterator(this.projects);}
}public class Client {public static void main(String[] args) {Project project new Project();project.add(王者荣耀, 1000, 1000000);project.add(英雄联盟, 2000, 2000000);project.add(魔兽世界, 3000, 3000000);IProjectIterator iterator project.iterator();while (iterator.hasNext()){IProject next (IProject) iterator.next();System.out.println(next.getProductInfo());}}
}十五、组合模式
1. 定义
组合模式又叫部分-整体模式该模式将对象组合成树形结构以表示“部分-整体”的层次结构适用于维护和展示部分-整体关系的场景。 组合模式通用UML类图如下核心点就是一个整体对象中添加一个部分对象。 实现代码如下
public abstract class AComponent {public void operation(){//do something}
}public class Composite extends AComponent{private ArrayListAComponent subListnew ArrayList();public void add(AComponent component){this.subList.add(component);}public void remove(AComponent component){this.subList.remove(component);}public ArrayListAComponent getChild(){return this.subList;}
}public class Leaf extends AComponent{Overridepublic void operation() {super.operation();}
}public class Client {public static void main(String[] args) {Composite rootnew Composite();root.operation();Composite branchnew Composite();Leaf leafnew Leaf();root.add(branch);branch.add(leaf);}//递归遍历从上往下private static void display(Composite root){for (AComponent component : root.getChild()) {if (component instanceof Leaf){component.operation();}else {display((Composite) component);}}}
}2. 案例
设计一个程序去整理公司如下图的组织架构。
2.1 普通的设计方案
很简单嘛。公司组织架构就是一颗树而一棵树包括树根树枝树叶三种对象直接拍脑袋想到的UML类图如下:
核心实现代码如下
public class Root implements IRoot{private ArrayList subListnew ArrayList();private String name;private String position;private int salary;public Root(String name, String position, int salary) {this.name name;this.position position;this.salary salary;}Overridepublic String getInfo() {return 名称this.name\t职位this.position\t薪水this.salary;}Overridepublic void add(IBranch branch) {this.subList.add(branch);}Overridepublic void add(ILeaf leaf) {this.subList.add(leaf);}Overridepublic ArrayList getSubInfo() {return this.subList;}
}public class Leaf implements ILeaf{private String name;private String position;private int salary;public Leaf(String name, String position, int salary) {this.name name;this.position position;this.salary salary;}Overridepublic String getInfo() {return 名称this.name\t职位this.position\t薪水this.salary;}
}public class Client {public static void main(String[] args) {//创造节点IRoot ceonew Root(王麻子,总经理,100000);IBranch devDepnew Branch(刘瘸子,研发经理,10000);IBranch saleDepnew Branch(张瘸子,销售经理,8000);IBranch moneyDepnew Branch(赵驼背,财务经理,8000);IBranch firstDevGroupnew Branch(刘能,开发一组组长,9000);IBranch secondDevGroupnew Branch(张能,开发二组组长,9000);ILeaf anew Leaf(a,开发人员,2000);ILeaf bnew Leaf(b,开发人员,2000);ILeaf cnew Leaf(c,开发人员,2000);ILeaf dnew Leaf(d,开发人员,2000);ILeaf enew Leaf(e,开发人员,2000);ILeaf fnew Leaf(f,开发人员,2000);ILeaf gnew Leaf(g,开发人员,2000);ILeaf hnew Leaf(h,销售人员,5000);ILeaf inew Leaf(i,销售人员,5000);ILeaf jnew Leaf(j,财务人员,6000);ILeaf knew Leaf(k,CEO秘书,8000);ILeaf devDognew Leaf(研发部狗腿子,研发部副总,9000);//构造树ceo.add(devDep);ceo.add(saleDep);ceo.add(moneyDep);ceo.add(k);devDep.add(firstDevGroup);devDep.add(secondDevGroup);devDep.add(devDog);firstDevGroup.add(a);firstDevGroup.add(b);firstDevGroup.add(c);secondDevGroup.add(d);secondDevGroup.add(e);secondDevGroup.add(f);moneyDep.add(j);saleDep.add(h);saleDep.add(i);System.out.println(ceo.getInfo());getAllSubInfo(ceo.getSubInfo());}private static void getAllSubInfo(ArrayList subList){for (Object o : subList) {if (o instanceof Leaf){System.out.println(((Leaf) o).getInfo());}else {Branch branch (Branch) o;System.out.println(branch.getInfo());getAllSubInfo(branch.getSubInfo());}}}
}2.2 改进的设计方案
上面的普通方案用脑子再稍微微想一想就知道树枝和树根的结构其实一模一样干嘛还有两个所以可以合为一个然后每个对象中都有getInfo方法那么我们应该把它提出来封装改进后的UML类图如下 核心实现代码如下
public class Branch implements IBranch{private String name;private String position;private int salary;ArrayListICrop subListnew ArrayList();public Branch(String name, String position, int salary) {this.name name;this.position position;this.salary salary;}Overridepublic void add(ICrop crop) {subList.add(crop);}Overridepublic ArrayList getSubInfo() {return this.subList;}Overridepublic String getInfo() {return 名称this.name\t职位this.position\t薪水this.salary;}
}2.3 采用组合模式的设计方案
采用组合模式对2.2的方案再改进UML类图如下 核心实现代码如下
public abstract class ACrop {private String name;private String position;private int salary;public ACrop(String name, String position, int salary) {this.name name;this.position position;this.salary salary;}public String getInfo(){return 名称this.name\t职位this.position\t薪水this.salary;}
}public class Branch extends ACrop{private ArrayListACrop subListnew ArrayList();public Branch(String name, String position, int salary) {super(name, position, salary);}public void add(ACrop crop){this.subList.add(crop);}public ArrayList getSubInfo(){return this.subList;}
}public class Leaf extends ACrop{public Leaf(String name, String position, int salary) {super(name, position, salary);}
}3. 扩展
常规的组合模式可以很方便实现从上到下遍历数据但是想要实现从下往上遍历数据我们就需要在组合模式的基础稍微扩展下只需要给每个对象添加它的父对象即可UML类图如下 核心实现代码如下
public abstract class AComponent {AComponent parent;public void operation(){}protected void setParent(AComponent component){this.parentcomponent;}public AComponent getParent(){return this.parent;}
}public class Composite extends AComponent {private ArrayListAComponent subListnew ArrayList();public void add(AComponent component){component.setParent(this);this.subList.add(component);}public void remove(AComponent component){this.subList.remove(component);}public ArrayListAComponent getChild(){return this.subList;}
}十六、状态模式
1. 定义
当一个对象内在状态改变时其行为随之改变。适用于存在大量的case情况每种case就是一种状态且更能方便的处理case之间的切换条件。 状态模式通用UML类图如下 其中AState是各个状态的抽象类角色Context是暴露给客户端的环境角色用户在Conetext中切换状态的同时内部会进行状态切换随之导致Context行为的改变。核心实现代码如下
public abstract class AState {//当前环境角色提供子类访问protected Context context;public void setContext(Context context){this.contextcontext;}public abstract void handle1();public abstract void handle2();
}public class ConcreteState1 extends AState{Overridepublic void handle1() {//本状态下必须处理的逻辑}Overridepublic void handle2() {//状态切换super.context.setCurrentState(Context.STATE2);super.context.handle2();}
}public class ConcreteState2 extends AState{Overridepublic void handle1() {//状态切换super.context.setCurrentState(Context.STATE1);super.context.handle1();}Overridepublic void handle2() {//本状态必要的操作}
}public class Context {public final static AState STATE1new ConcreteState1();public final static AState STATE2new ConcreteState2();private AState CurrentState;//该方法可要可不要使用这个方法只是使得逻辑更好理解public AState getCurrentState() {return CurrentState;}public void setCurrentState(AState currentState) {this.CurrentState currentState;this.CurrentState.setContext(this);}//委托行为public void handle1(){this.CurrentState.handle1();;}public void handle2(){this.CurrentState.handle2();}}2. 案例
以电梯为例电梯通常有开门关门运行停止这样四个状态但是各个状态直接的切换其实都有一定的条件如开门状态下正常情况下肯定不能切换到运行状态涉及多个状态直接转换采用状态模式再合适不过采用状态模式设计该案例的UML类图如下 核心实现代码如下
public abstract class ALiftState {protected Context context;public void setContext(Context context){this.contextcontext;}public abstract void open();public abstract void close();public abstract void run();public abstract void stop();
}public class Context {public final static OpeningState openingStatenew OpeningState();public final static ClosingState closingStatenew ClosingState();public final static RunningState runningStatenew RunningState();public final static StoppingState stoppingStatenew StoppingState();private ALiftState liftState;ALiftState getLiftState(){return liftState;}void setLiftState(ALiftState liftState){this.liftStateliftState;this.liftState.setContext(this);}void open(){this.liftState.open();}void close(){this.liftState.close();}void run(){this.liftState.run();}void stop(){this.liftState.stop();}
}public class StoppingState extends ALiftState{Overridepublic void open() {super.context.setLiftState(Context.openingState);super.context.open();}Overridepublic void close() {System.out.println(电梯此时不能执行关闭操作...);}Overridepublic void run() {super.context.setLiftState(Context.runningState);super.context.run();}Overridepublic void stop() {System.out.println(电梯停止...);}
}public class Client {public static void main(String[] args) {Context context new Context();context.setLiftState(Context.closingState);context.open();context.run();context.close();context.run();context.stop();}
}3. 优缺点
优点
结构清晰避免过多的case语句提高系统的可维护性。满足开闭原则和单一职责原则需要增加一种状态只需要实现一个子类即可封装性好外部调用不需要知道内部如何进行状态切换。
缺点 缺点也很明显对于过多的状态会造成类膨胀问题。
十七、解释器模式
这个模式理解起来可能有点费劲且它的使用很少所以能搞懂就搞懂吧不能搞懂也就算了但最好能搞懂这种模式的思想。
1. 定义
解释器模式是一种按照规定语法进行解析的方案其实就是简单语法分析工具。比如四则运算就是一种规定语法我们要实现对其计算就可以采用解释器模式以四则运算为例它的表达式包括两种要素一种是数值终结表达式一种是符号非终结表达式那么我们就需要对这两种表达式进行解析。 解释器模式通用的UML类图如下主要是对各种表达式进行解析AbstractExpression然后用Context对其封装Client调用Context完成对一种文法的解析。
2. 案例
输入任意一个模型公式本案例只需要加减即可输入对应的参数值运算出结果。 给定一个公式然后实现该公式的计算非常简单但是实现对任意公式的计算就不是那么简单了这就需要你写的代码具有良好的扩展性此时采用解释器模式最合适不过也可以理解为解释器模式就是为了这种需求而产生的。 采用解释器模式实现加减运算的UML类图如下 实现代码如下
public abstract class Expression {public abstract int interpreter(HashMapString,Integer var);
}//解析数值表达式
public class VarExpression extends Expression{private String key;public VarExpression(String key) {this.key key;}Overridepublic int interpreter(HashMapString, Integer var) {return var.get(key);}
}//解析符号表达式
public abstract class SymbolExpression extends Expression {protected Expression left;protected Expression right;public SymbolExpression(Expression left, Expression right) {this.left left;this.right right;}
}//加号解释器
public class AddSymbolExpression extends SymbolExpression{public AddSymbolExpression(Expression left, Expression right) {super(left, right);}Overridepublic int interpreter(HashMapString, Integer var) {return left.interpreter(var) right.interpreter(var);}
}//减号解释器
public class SubSymbolExpression extends SymbolExpression{public SubSymbolExpression(Expression left, Expression right) {super(left, right);}Overridepublic int interpreter(HashMapString, Integer var) {return super.left.interpreter(var)- super.right.interpreter(var);}
}/*** 封装表达式计算逻辑*/
public class Calculator {private Expression expression;public Calculator(String expStr) {//自构建公式StackExpression stack new Stack();char[] chars expStr.toCharArray();Expression left null;Expression right null;for (int i 0; i chars.length; i) {switch (chars[i]){case :leftstack.pop();rightnew VarExpression(String.valueOf(chars[i]));stack.push(new AddSymbolExpression(left,right));break;case -:leftstack.pop();rightnew VarExpression(String.valueOf(chars[i]));stack.push(new SubSymbolExpression(left,right));break;default:stack.push(new VarExpression(String.valueOf(chars[i])));}}this.expressionstack.pop();}/*** 传入具体符号对应的数据key代表符号value代表值* param var* return*/public int run(HashMapString,Integer var){//递归计算return this.expression.interpreter(var);}
}public class Client {public static void main(String[] args) {//输入表达式String expStr getExpStr();//输入数据HashMapString, Integer data getValue(expStr);//计算公式Calculator calculator new Calculator(expStr);int result calculator.run(data);System.out.println(运行结果为 result);}/*** 键盘输入表达式** return*/public static String getExpStr() {System.out.println(请输入表达式);try {return new BufferedReader(new InputStreamReader(System.in)).readLine();} catch (IOException e) {throw new RuntimeException(e);}}/*** 输入数据并以Map的形式组织数据** param expStr* return*/public static HashMapString, Integer getValue(String expStr) {HashMapString, Integer data new HashMap();char[] chars expStr.toCharArray();for (char aChar : chars) {if (aChar ! aChar ! -) {if (!data.containsKey(aChar)) {try {System.out.print(请输入 aChar 的值: );String in new BufferedReader(new InputStreamReader(System.in)).readLine();data.put(String.valueOf(aChar), Integer.parseInt(in));} catch (IOException e) {throw new RuntimeException(e);}}}}return data;}
}运行代码示例
请输入表达式
abc-d
请输入a的值: 1
请输入b的值: 1
请输入c的值: 1
请输入d的值: 1
运行结果为23. 优缺点
优点 解释器是一个简单语法分析工具 它最显著的优点就是扩展性 修改语法规则只要修改 相应的非终结符表达式就可以了 若扩展语法 则只要增加非终结符类就可以了 缺点
非终结表达式多的话会造成类膨胀解释器模式采用的是递归调用这导致它的调试很复杂且效率不高 总结解释器模式很少自己实现了因为自己简单的实现存在很多缺点但是它的思想还是值得学习的如果遇到需要使用解释器模式的场景可以使用现有的开源解析工具包或者脚本语言代替。
十八、门面模式
1. 定义
门面模式非常简单就是将复杂的子系统交互全部封装到一个门面类中外界只能通过这个门面类访问子系统。 门面模式通用类图如下所示门面类其实就是子系统的一个委托对象。
2. 案例
比如我们实现写一份信的过程最直接的实现类图如下 客户端直接访问写信的各个过程那么客户端需要知道步骤顺序否则这封信就发不出去其次扩展性极差。 采用门面模式实现写信过程的类图如下所示 客户端只能访问ModernPostOffice且通过ModernPostOffice直接实现写信的全过程不需要知道细节且扩展容易如扩展检查信封的功能只需要将Police类组合到ModernPostOffice中即可。 核心实现代码如下
public interface ILetterProcess {void write(String context);void envelope(String address);void postBox();void send();
}public class ModernPostOffice {private ILetterProcess letterProcessnew LetterProcessImpl();private Police policenew Police();public void sendLetter(String context,String address){letterProcess.write(context);letterProcess.envelope(address);police.check(letterProcess);letterProcess.postBox();letterProcess.send();}
}public class Client {public static void main(String[] args) {ModernPostOffice modernPostOffice new ModernPostOffice();modernPostOffice.sendLetter(你好好久不见,南京市建邺区XXX);}
}