共计 6979 个字符,预计需要花费 18 分钟才能阅读完成。
ps:本文系转载文章,浏览原文可获取源码,文章开端有原文链接
ps:这一篇是写备忘录模式、中介者模式和解释器模式
1、备忘录模式
在放弃封装性的条件下,获取一个对象的外部状态,在其余中央保留这个对象的状态,当须要用到该对象状态时就复原到原先保留的状态。
备忘录模式具备以下几种角色:
(1)发起人角色:记录以后的外部状态,具备创立备忘录和复原备忘录的办法。
(2)备忘录角色:存储发起人的外部状态,在须要用到的时候返回这些外部状态给发起人。
(3)管理者角色:对备忘录进行治理,只提供保留与获取备忘录的办法。
上面用代码举个例子:
(1)发起人角色,新建一个 Emp 类:
public class Emp {
private String ename;
private int age;
private double salary;
public Emp(String ename, int age, double salary) {
super();
this.ename = ename;
this.age = age;
this.salary = salary;
}
public EmpMemento memento() {
return new EmpMemento(this);
}
public void recovery(EmpMemento e) {
this.ename = e.getEname();
this.age = e.getAge();
this.salary = e.getSaraly();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
(2)备忘录角色,新建一个 EmpMemento 类:
public class EmpMemento {
private String ename;
private int age;
private double saraly;
public EmpMemento(Emp emp) {
ename = emp.getEname();
age = emp.getAge();
saraly = emp.getSalary();
}
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public double getSaraly() {
return saraly;
}
public void setSaraly(double saraly) {
this.saraly = saraly;
}
}
(3)管理者角色,新建一个 CareTaker 类:
public class CareTaker {
private EmpMemento memento;
public EmpMemento getMemento() {
return memento;
}
public void setMemento(EmpMemento memento) {
this.memento = memento;
}
}
(4)客户端进行测试调用:
CareTaker taker = new CareTaker();
Emp emp = new Emp("小周", 11, 300);
System.out.println("第一次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
taker.setMemento(emp.memento());
System.out.println("曾经保留了之前的数据,当初对数据进行批改");
emp.setEname("小二");
emp.setAge(19);
emp.setSalary(99);
System.out.println("第二次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
System.out.println("正在撤销,复原之前保留的数据");
emp.recovery(taker.getMemento());
System.out.println("第三次打印" + emp.getEname() + "---" + emp.getAge() + "---" + emp.getSalary());
日志打印如下所示:
图片
首先一开始就实例化一个发起人角色 Emp,它的外部状态就是 ename、age 和 salary 属性,发起人角色创立备忘录角色 EmpMemento,顺便把本人的状态赋值给 EmpMemento 的状态,而后管理者角色 CareTaker 就把备忘录角色 EmpMemento 存储起来;当咱们把发起人角色 Emp 的状态批改后,咱们要想复原之前的状态,就必须通过 CareTaker 的 getMemento 办法获取发起人角色 Emp,并通过 Emp 的 recovery 办法最终实现复原之前的状态
;这个就像咱们用文件编辑文字一样,咱们要想复原上一次编辑的记录,就按下 Ctrl + z 就能撤回到上一次的记录了。
备忘录模式尽管给用户提供了一种能够复原状态的机制,能够使用户可能比拟不便地回到某个历史的状态;实现了信息的封装,使得用户不须要关怀状态的保留细节,且状态信息都保留到备忘录里由管理者治理;然而如果类的成员变量过多,会占用很大的资源,同时保留也会耗费肯定的内存;改变也很麻烦,当发起人角色的状态产生扭转时,备忘录角色的状态也会产生扭转。
2、中介者模式
用一个中介对象来封装一系列对象的交互过程,中介者使各对象能够隐式的互相援用,使其耦合涣散,而且扭转它们之间的交互是独立的。
中介者模式具备以下几种角色:
(1)形象中介者角色:具体中介者要实现的接口,定义了共事对象注册和发送给共事对象信息的形象办法。
(2)具体中介者角色:实现形象中介者角色的子类,申明一个容器来治理共事对象,帮助共事类角色的交互,它依赖于共事角色。
(3)形象共事类角色:申明具体共事类角色要实现的接口,定义共事对象交互的形象办法。
(4)具体共事类角色:形象共事类角色的子类,实现形象共事类角色所有的形象办法,须要与其余共事对象进行交互时,由中介者对象帮助。
上面用代码举个例子:
(1)形象中介者角色,新建一个 Mediator 接口:
public interface Mediator {
public void register(String name,Department d);
public void command(String name);
}
(2)形象共事类角色,新建一个 Department 接口:
public interface Department {
public void selfAction();
public void outAction();
}
(3)具体中介者角色,新建一个 President 类并实现 Mediator 接口:
public class President implements Mediator{
private Map<String, Department> map = new HashMap<String, Department>();
@Override
public void register(String name, Department d) {
map.put(name, d);
}
@Override
public void command(String name) {
map.get(name).selfAction();
}
}
(4)具体共事类角色,新建一个 Market 类并实现 Department 接口:
public class Market implements Department{
private Mediator mediator;
public Market(Mediator mediator) {
this.mediator = mediator;
mediator.register("market", this);
}
@Override
public void selfAction() {
System.out.println("Market--- 跑市场");
}
@Override
public void outAction() {
System.out.println("Market--- 汇报工作,我的项目正在进度");
mediator.command("finacial");
mediator.command("development");
}
}
(5)具体共事类角色,新建一个 Finacial 类并实现 Department 接口:
public class Finacial implements Department{
public Finacial(Mediator mediator) {
mediator.register("finacial", this);
}
@Override
public void selfAction() {
System.out.println("Finacial--- 数钱");
}
@Override
public void outAction() {
System.out.println("Finacial--- 汇报工作,出账");
}
}
(6)具体共事类角色,新建一个 Development 类并实现 Department 接口:
public class Development implements Department{
public Development(Mediator mediator) {
mediator.register("development", this);
}
@Override
public void selfAction() {
System.out.println("Development--- 分心科研项目");
}
@Override
public void outAction() {
System.out.println("Development--- 没钱了,须要资金反对");
}
}
(7)客户端进行测试调用:
Mediator mediator = new President();
Market market = new Market(mediator);
new Finacial(mediator);
new Development(mediator);
market.selfAction();
market.outAction();
日志打印如下所示:
图片
首先实例化一个中介者角色对象 mediator(实现类是 President),而后实例化具体共事类角色对象 new Market(mediator)、new Finacial(mediator) 和 new Development(mediator),并顺便把这些实例化具体共事类角色对象注册到中介者角色对象 mediator 中,此时具体共事类角色对象就会被保留到 Mediator 的实现类 President 的 Map 容器中;当 Market 调用 outAction 办法时,在该办法外部顺便通过中介者 mediator 的 command 办法调用 Finacial 的 outAction 办法和 Development 的 outAction 办法,最终实现了中介者模式的成果。
中介者模式尽管使类变得简略,将一对多转化成了一对一的关联,升高了各个类之间的耦合性,遵循迪米特准则;然而中介者会宏大,变得复杂难以保护,当共事类越多时,中介者就会越臃肿,每增加一个共事类,调用共事类的中介者很有可能要批改。
3、解释器模式
定义一个语言,定义它的文法示意,再定义一个解释器,这个解释器用来解释语言中的句子。
解释器模式具备以下几种角色:
(1)形象表达式角色:申明解释器的接口,标准解释器的解释行为。
(2)终结符表达式角色:是形象表达式的子类,用来实现文法中与终结符相干的操作。
(3)非终结符表达式角色:是形象表达式的子类,用来实现文法中与非终结符相干的操作,它最终也是调用文法中与终结符相干的操作。
(4)环境角色:个别蕴含传递被所有解释器共享的数据或是公共的性能。
上面用代码举个例子:
(1)形象表达式角色,新建一个 Expression 接口:
public interface Expression {
public boolean interpret(String s);
}
(2)终结符表达式角色,新建一个 TerminalExpression 类并实现 Expression 接口:
public class TerminalExpression implements Expression {
private Set<String> set = new HashSet<String>();
public TerminalExpression(String[] data) {
for (int i = 0; i < data.length; i++)
set.add(data[i]);
}
public boolean interpret(String info) {
if (set.contains(info)) {return true;}
return false;
}
}
(3)非终结符表达式角色,新建一个 AndExpression 类并实现 Expression 接口:
public class AndExpression implements Expression {
private Expression city = null;
private Expression person = null;
public AndExpression(Expression city, Expression person) {
this.city = city;
this.person = person;
}
public boolean interpret(String info) {
String s[] = info.split("的");
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
(4)环境角色,新建一个 Context 类:
public class Context {
private String[] citys = { “ 深圳 ”, “ 东莞 ”};
private String[] persons = { “ 老人 ”, “ 学生 ”, “ 儿童 ”};
private Expression cityPerson;
public Context() {
Expression city = new TerminalExpression(citys);
Expression person = new TerminalExpression(persons);
cityPerson = new AndExpression(city, person);
}
public void freeRide(String info) {
boolean b = cityPerson.interpret(info);
if (b) {System.out.println("这是" + info + ",本次进园游览打 5 折!");
} else {System.out.println(info + ",不属于享半价优惠人员,按原价免费");
}
}
}
(5)客户端进行测试调用:
Context c = new Context();
c.freeRide("深圳的老人");
c.freeRide("东莞的年轻人");
c.freeRide("北京的妇女");
c.freeRide("上海的儿童");
c.freeRide("东莞的学生");
日志打印如下所示:
图片
首先实例化一个 Context 对象,在其构造方法中实例化 2 个终结符表达式角色对象 TerminalExpression 并传递字符串数组 citys 和 persons,创立好 2 个 TerminalExpression 对象之后,而后再创立非终结符表达式角色对象 AndExpression 并把 2 个 TerminalExpression 对象作为参数传入到它(AndExpression)的构造方法中;最初调用 Context 对象的 freeRide 办法,freeRide 办法的调用过程是这样的 freeRide –> AndExpression.interpret–> TerminalExpression.interpret,最终由终结符表达式角色 TerminalExpression 来解释语言中的句子;在这过程中 AndExpression 的 interpret 办法将“的”字切割进去,而后用 city.interpret 办法判断中央,person.interpret 判断年龄段的人。
尽管解释器模式在解释器模式中应用类来展现语言的文法规定,通过继承能够让拓展性变得更好,语法树中的表达式节点类是类似的,比拟好实现;然而它会引起类收缩,采纳递归调用办法档次太多会容易呈现栈溢出,可利用场景比拟少。