关于java:23种设计模式Java版第八篇

31次阅读

共计 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 判断年龄段的人。

尽管解释器模式在解释器模式中应用类来展现语言的文法规定,通过继承能够让拓展性变得更好,语法树中的表达式节点类是类似的,比拟好实现;然而它会引起类收缩,采纳递归调用办法档次太多会容易呈现栈溢出,可利用场景比拟少。

正文完
 0