快捷搜索:  as  test  1111  test aNd 8=8  test++aNd+8=8  as++aNd+8=8  as aNd 8=8

澳门威利斯人网站44_酒文化网进入



惯用模式可所以 技巧也可所以 领域。技巧模式为常用的技巧软件问题指出办理规划,例如在利用法度榜样(或利用法度榜样套件)中如何处置澳门威利斯人网站44惩罚验证、安然和事务数据。前几期主要关注获取技巧惯用模式所用的技巧,例如元法度榜样设计。域模式关注的是若何抽象常见营业问题。而技巧模式险些呈现在所有的软件中,域模式之间的差异与营业之间的差异一样大年夜。然而获取它们有一套富厚的技巧,这便是本期以及后续几期将要讨论的话题。

本文为应用 DSL 技巧作为一种抽象样式获取域模式供给动力,DSL 供给多种选择,包括自己命名的模式。Martin Fowler 近来的一本书对 DSL 技巧有较为深入的钻研。在后续几期中,我会应用他的许多模式名,也会将他的示例用于我的例子中,慢慢讲述详细技巧。

DSL 的念头

为什么我们要费那么多周折创建一个 DSL澳门威利斯人网站44 ?仅仅为了获取一个惯用模式?正如我在 “使用可重用代码,第 2 部分” 中指出的,区分惯用模式的最好措施便是让它看起来与其他代码不一样。这种看得见的不合是最直接的线索,您不必要再看老例 API。同样,应用 DSL 的目的之一是写代码,使这些代码看起来不像源代码而更像您正在考试测验办理的问题。假如能够达到这个目标(或者靠近这个目标),那您将填补软件项目中的这一空缺,为开拓职员和营业涉众的沟通架起了桥梁。容许用户涉猎您的代码很有需要,由于这打消了将代码转换为说话的需求,这是项很轻易掉足的事情。让您的代码对付非技巧职员是易读的,由于他们懂得软件的预期设想,这样你们之间就会有更多的交流。

为勉励开拓职员应用这种技巧,我将借用 Fowler DSL 书中的例子。假设我正为一家制作软件节制的暗格(secret compartments,想想 James Bond)的公司事情。公司的一个客户,H. 夫人,想要在她的睡房里装一个暗格。然而我们公司应用 .com 泡沫破裂后留下的 Java™驱动的 toasters 来运行软件。只管 toasters 对照便宜,但更新此中的软件却很昂贵,是以我必要创建根基暗格代码,然后将其永远地设置在 toasters 上,然后找到一种措施根据每位用户的需求进行设置设置设备摆设摆设。您也知道,在今世软件天下中,这是一个很常见的问题:普遍行径不常改变,而设置设置设备摆设摆设必要根据小我环境进行改变。

H. 夫人想要一个暗格,打开这个暗格的措施是:首先关闭睡房门,接着打开装扮台的第二个抽屉,着末打开床头灯。这些活动必须依次进行,假如打乱序次,必须重头开始。您可以将节制暗格的软件想象为一个状态机,如图 1 所示:

图 1. H. 夫人的暗格是状态机

基础状态机 API 对照简单。创建一个抽象事故类,可以同时处置惩罚状态机内的事故和敕令,如清单 1 所示:

清单 1. 状态机的抽象事故

public class AbstractEvent {

private String name, code;

public AbstractEvent(String name, String code) {

this.name = name;

this.code = code;

}

public String getCode() { return code;}

public String getName() { return name;}

可以应用另一个简单类 States对状态机中的状态建模,如清单 2 所示 :

清单 2. 状态机类的开始部分

public class States {

private State content;

private List

transitions = new ArrayList

();

private List commands = new ArrayList();

public States(String name, StateMachineBuilder builder) {

super(name, builder);

content = new State(name);

}

State getState() {

return content;

}

public States actions(Commands... identifiers) {

builder.definingState(this);

commands.addAll(Arrays.asList(identifiers));

return this;

}

public TransitionBuilder transition(Events identifier) {

builder.definingState(this);

return new TransitionBuilder(this, identifier);

}

void addTransition(TransitionBuilder arg) {

transitions.add(arg);

}

void produce() {

for (Commands c : commands)

content.addAction(c.getCommand());

for (TransitionBuilder t : transitions)

t.produce();

}

}

清单 1和 清单 2仅做参考。必要办理的问题是若何表示状态澳门威利斯人网站44机的设置设置设备摆设摆设。这种表示是安装暗格的一种惯用模式。清单 3 展示了状态机基于 Java 的设置设置设备摆设摆设:

清单 3. 一个设置设置设备摆设摆设选择:Java 代码

Event doorClosed = new Event("doorClosed", "D1CL");

Event drawerOpened = new Event("drawerOpened", "D2OP");

Event lightOn = new Event("lightOn", "L1ON");

Event doorOpened = new Event("doorOpened", "D1OP");

Event panelClosed = new Event("panelClosed", "PNCL");

Command unlockPanelCmd = new Command("unlockPanel", "PNUL");

Command lockPanelCmd = new Command("lockPanel", "PNLK");

Command lockDoorCmd = new Command("lockDoor", "D1LK");

Command unlockDoorCmd = new Command("unlockDoor", "D1UL");

State idle = new State("idle");

State activeState = new State("active");

State waitingForLightState = new State("waitingForLight");

State waitingForDrawerState = new State("waitingForDrawer");

State unlockedPanelState = new State("unlockedPanel");

StateMachine machine = new StateMachine(idle);

idle.addTransition(doorClosed, activeState);

idle.addAction(unlockDoorCmd);

idle.addAction(lockPanelCmd);

activeState.addTransition(drawerOpened, waitingForLightState);

activeState.addTransition(lightOn, waitingForDrawerState);

waitingForLightState.addTransition(lightOn, unlockedPanelState);

waitingForDrawerState.addTransition(drawerOpened, unlockedPanelState);

unlockedPanelState.addAction(unlockPanelCmd);

unlockedPanelState.addAction(lockDoorCmd);

unlockedPanelState.addTransition(panelClosed, idle);

machine.addResetEvents(doorOpened);

清单 3显示了应用 Java 进行状态机设置设置设备摆设摆设的几个问题。首先,涉猎这些 Java 代码并不能明确知道这便是状态机设置设置设备摆设摆设,和多半 Java API 一样,这只是一堆没有差其余代码。第二,冗长且重复。为状态机的每部分设置更多的状态和转换时,变量名重复应用,所有这些重复使代码难于涉猎。第三,代码不能满意最初目标 —— 无需从新编译就可设置设置设备摆设摆设暗格。

事实上,在 Java 天下险些看不到这种代码了,现在盛行应用 XML 编写设置设置设备摆设摆设代码。用 XML 编写设置设置设备摆设摆设很简单,如清单 4 所示:

清单 4. 用 XML 编写的状态机设置设置设备摆设摆设

清单 4中的代码比拟 Java 版本有几个上风。第一,延迟绑定,这意味着可以改动代码并将其放进 toaster,可以应用 XML 解析器涉猎设置设置设备摆设摆设。第二,对付这个特定问题,这段代码是更富于体现力,由于 XML 包孕容器(containership)观点:States 将它们的设置设置设备摆设摆设包孕为子元素。这有助于删除 Java 版本中令人憎恶的冗余。第三,代码本色上是声明式的。平日,假如您只是进行声明而不必要 if和 while语法,声明式代码更易于涉猎。

暂时退后一步,先理解其含义。外化设置设置设备摆设摆设在今世 Java 天下中是一种很常见的模式,我们不再觉得它是独特实体。实际上这也是每个 Java 框架的特性。设置设置设备摆设摆设是一个惯用模式,我们必要捕获要领,使其差别于周围框架的一样平常行径,并将其分离出来。应用 XML 进行设置设置设备摆设摆设,我是应用外部 DSL 编写代码的(句法 [syntax] 是 XML,语法 [grammar] 是由 XML 相关模式定义的),是以不必要从新编译框架代码对其进行转换。

我们没有需要由于 XML 的上风,老是应用 XML。可以斟酌以下设置设置设备摆设摆设代码,如清单 5 所示:

清单 5. 定制语法(custom-grammar)的状态机设置设置设备摆设摆设

events

doorClosed D1CL

drawerOpened D2OP

lightOn   L1ON

doorOpened D1OP

panelClosed PNCL

end

resetEvents

doorOpened

en澳门威利斯人网站44d

commands

unlockPanel PNUL

lockPanel  PNLK

lockDoor  D1LK

unlockDoor D1UL

end

state idle

actions {unlockDoor lockPanel}

doorClosed => active

end

state active

drawerOpened => waitingForLight

lightOn  => waitingForDrawer

end

state waitingForLight

lightOn => unlockedPanel

end

state waitingForDrawer

drawerOpened => unlockedPanel

end

state unlockedPanel

actions {unlockPanel lockDoor}

panelClosed => idle

end

XML 版本有的上风,它也有:是声明式的,有容器观点,并且是简明的。同时它也逾越了 XML 和 Java 版本,由于它很少有 噪音字符(例如 ),只管这对技巧实现是必需的,然则影响可读性。

此版设置设置设备摆设摆设代码是一个用 ANTLR 编写的定制外部 DSL,也是一个开源对象,它使得用自定义说话编写变得很轻易。曾经在大年夜学时刻不爱好编译器(包括诸如 Lex 和 YACC 之类的经典对象)课程的人,将很痛快知道这些对象已经变得很多多少了。这个例子来自 Fowler 的书中,他说构建 XML 版本和构建定制说话版本所用光阴相同。

清单 6 中的是用 Ruby 写的另一种可选版本 :

清单 6. JRuby 中的状态机设置设置设备摆设摆设

event :doorClosed, "D1CL"

event :drawerOpened, "D2OP"

event :lightOn, "L1ON"

event :doorOpened, "D1OP"

event :panelClosed, "PNCL"

command :unlockPanel, "PNUL"

command :lockPanel, "PNLK"

command :lockDoor, "D1LK"

command :unlockDoor, "D1UL"

resetEvents :doorOpened

state :idle do

actions :unlockDoor, :lockPanel

transitions :doorClosed => :active

end

state :active do

transitions :澳门威利斯人网站44drawerOpened => :waitingForLight,

:lightOn => :waitingForDrawer

end

state :waitingForLight do

transitions :lightOn => :unlockedPanel

end

state :waitingForDrawer do

transitions :drawerOpened => :unlockedPanel

end

state :unlockedPanel do

actions :unlockPanel, :lockDoor

transitions :panelClosed => :idle

end

免责声明:以上内容源自网络,版权归原作者所有,如有侵犯您的原创版权请告知,我们将尽快删除相关内容。

您可能还会对下面的文章感兴趣: