演员网站_演员们还可以!

演员网站

我认为这种陌生和恐吓至少没有什么根据,因为我知道许多人,甚至大多数程序员,都使用了与Actor模型非常相似的范例。 我想了解您之前所做的事情,并提请大家注意共同点。 让我解释。

GUI使用消息传递和参与者

我认为可以肯定地认为,几乎每个阅读本书的人都在图形用户界面或GUI上进行了一些编程。 也许您的GUI经验可以追溯到原始Windows API或X Window System的时代。 如果没有,您可能已经在浏览器上使用了Swing或SWT甚至Javascript DOM进行了一些工作。 它们都有相似的概念和编程模型,但让我们以Windows API为例。

演员们在“确定”的最佳含义中是确定的,就像很棒的那样。


Windows API具有消息循环,该消息循环将排队的GUI交互消息(例如键盘按键和鼠标单击)分派到支持事件发生窗口的代码。 例如,当用户单击窗口上的鼠标按钮时,该鼠标单击事件将分派给注册为该窗口的消息处理程序的代码。 这既是事件驱动的编程,也是消息驱动的编程。

现在,将每个窗口都视为一个演员。 什么是演员? 角色是对象,类似于您使用面向对象的语言所使用的对象。 但是,参与者不接受直接方法调用。 相反,要请求演员的某些行为,您必须向其发送消息。 消息异步传递给参与者。 您可以在此处此处的其他一些博客文章中获得有关演员的更多详细信息。

因此,如果GUI窗口是角色,则显示器上的角色正在接收有关用户手势的消息,这些消息可能对执行应用程序行为有用。

您可能想知道为什么我选择使用Windows API作为示例,而不是使用更现代的GUI API。 事实是,Windows API仍然有意义。 但是,我的原因是我想特别提请您注意这种编程模型的长期存在。 Actor模型的非常概念已经使用了很长时间。

在C语言中,每个窗口的已注册消息处理程序如下所示。

WindowProc(HWND hwnd, UINT uMsg, WPARAM wParam, LPARAM lParam)
{
   switch (uMsg)
   {
   case WM_CREATE:
   ...
   case WM_SIZE:
   ...
   case WM_LBUTTONDOWN:
   ...
   case WM_LBUTTONUP:
   ...
   }
}

我不会花很多时间来解释Windows API的详细信息,也不用解释现在令人恐惧的类型和变量的匈牙利符号(请注意,我省略了令人困惑的返回值)。 只需了解hwnd是接收消息的窗口的句柄(无符号int),而uMsg(无符号int)是消息类型。 每个uMsg可以有两个参数,一个是wParam(字或整数),一个是lParam(可以用作指向某些数据结构的指针的long)。 将hwnd视为窗口的ID或指针,可以将其用于向自己发送消息或将其包含在发送给其他窗口的消息的句柄中。

在上方,该窗口准备处理WM_CREATE消息,其中Windows告诉该窗口执行与正在创建的事情有关的事情,例如,创建其子窗口。 该窗口也可以响应用户调整大小,因为它处理WM_SIZE消息。 并且此窗口可以通过处理WM_LBUTTONDOWN和WM_LBUTTONUP来检测鼠标按钮的单击。 只需实施C代码来处理所有这些消息,您就会看到一个窗口,即鼓声… React性

等一下! 我是不是想告诉你,你,你可能一直在做无功编程样过的 ? 我是。

因此,不要被演员模型所吓倒。 演员就是这么简单。 你不相信我吗? 下面,我提供一些与上述C代码相同的Erlang代码(假定Erlang具有Windows API的本机协议)。 为什么选择Erlang? 因为Erlang是第一种真正的基于actor的编程语言,可在工业上使用,所以它对Actor模型的方法已被现代actor框架使用。

process(State = #state{}) ->
   receive
     {Sender, Message = #Create{}} ->
       ...
     {Sender, Message = #Resize{}} ->
       ...
     {Sender, Message = #LeftButtonDown{}} ->
       ...
     {Sender, Message = #LeftButtonUp{}} ->
       ...
   end.

在这里,参与者(实际上在Erlang中称为流程)在其process()函数中接收消息。 每当接收到新消息时,process()函数就会运行。 同样,我不会尝试解释Erlang代码,例如模式匹配,但是您可以看到Erlang代码映射到C代码而无需太多的Erlang知识。

这很有趣,不是吗? Windows API的外观和工作方式非常类似于Erlang进程/角色。

现在考虑上面在Java中使用vlingo / actors实现的相同问题。 同样,这假定存在适用于Java和vlingo / actor的Windows API的协议。 没有,但是如果是这样的话,演员将按照以下方式工作。

public class WindowActor extends Actor implements Window {
  public Result create(Specification spec) {
    ...
  }
  public Result resize(Size size) {
    ...
  }
  public Result leftButtonDown(Mouse mouse) {
    ...
  }
  public Result leftButtonUp(Mouse mouse) {
    ...
  }
}

再次,就是这么简单。 此外,您拥有熟悉的类型安全的Java代码,看起来就像您正在使用的代码一样。

但是Actor模型的异步性又如何呢? 这是否会使采用它变得更加复杂? 这里有一些要考虑的事实。

  • Actor模型是异步的,但是每个Actor在处理消息时的行为都类似于同步对象。 在角色内部,您拥有自己不受干扰的状态,并且一次仅处理一条消息。 没有种族。 在演员内部,您需要处理一个非常简单的世界,即成为演员协议的业务。
  • Windows环境和X Window以及您使用的任何GUI环境都是完全异步的。 您的窗口对收到的消息做出React。 它对外界几乎一无所知,它不受干扰地管理自己的状态,一次只处理一个消息。 它像演员一样工作,而演员也那样工作。

让它沉入。现在,为什么您对Actor Model感到恐惧? 您从事这种编程已经有好几年了,甚至几十年了。

调解员

现在是时候更深入地了解演员了。 我将向您介绍一些共同合作解决一个有趣问题的演员。 这个问题的中心是GoF Mediator模式的使用。

演员还可以

介体旨在解耦具有不同关注点的各种类型的组件。 GoF书中使用的经典示例通过具有多个可视组件的GUI来解释介体模式。 当我浏览相同的示例时,请将每个视觉组件视为一个演员。

  • 有一个DialogBox组件。 对话框具有四个子组件: 列表框; 确定按钮; 取消按钮。
  • 当对话框最初显示时,它具有:空白的文本框; 具有未选择项目的列表框; 禁用的确定按钮; 和一个启用的“取消”按钮。
  • “确定”按钮将保持禁用状态,直到在文本框中输入有效的条目为止。
  • 用户可以直接在文本框中输入一个值,或在列表框中选择一个项目,然后将该值放置在文本框中。 无论哪种情况,“确定”按钮都会启用。
  • 现在,用户可以单击“确定”以使“文本框”中的值返回给对话框的客户端。
  • 用户还可以双击列表框中的一个项目。 此手势使对话框做出响应,就像用户单击列表框项然后单击“确定”一样。

那么这将如何工作? 显然,在使各种可视组件在DialogBox内能够正常工作的过程中,肯定有一些特殊的行为。 一种选择是使每个字段类型组件成为要解决的给定问题的特殊类型。

因此,例如,列表框必须了解文本框,而文本框必须了解“确定”按钮。 当列表框检测到选择时,它将告诉文本框接受所选的项目文本。 然后,文本框将告诉“确定”按钮启用。 但是,如果列表框收到双击项怎么办? 列表框是否也应引用“确定”按钮并告诉“确定”按钮单击? 还是列表框将标记传递给文本框以告知它已收到双击选择,然后让文本框告诉确定,请单击确定,以得出对话框的体验?

还请参见:

! 我想您会同意这变得越来越混乱! 该怎么办? 现在是应用Mediator模式的时候了。 此模式要求解决方案中的一个组件充当所有其他组件之间的中介。 这意味着视觉组件之一必须了解所有其他组件,但其他组件对调解器的了解很少,而对于混合中的任何兄弟组件则一无所知。 这似乎是一个完美的解决方案,只是需要的东西。 考虑一下。

  • 对话框已经知道其所有子组件。 毕竟,当它收到其create()消息时,它就有机会创建每个子对象并在其表面上执行所需的布局。
  • 创建每个可视子组件时,将为其父窗口提供引用。 父窗口当然是DialogBox,但是子组件不知道。 子组件仅知道它们具有父窗口和对其的引用。
  • 对话框充当中介者。 当用户在子UI组件上执行各种手势时,这些子组件会向其父对话框DialogBox报告发生的情况。 然后,对话框通过将来自一个子组件的消息作为另一子组件上的行为进行中介,来管理各个组件的协作。

因此,介体模式可以很好地将每个子组件分离。 除了向父窗口报告操作外,每个孩子仅了解其需要的内容(例如列表框或文本框),而仅了解其内容。 孩子们甚至不知道他们的父母是一个DialogBox,只知道它是一个窗口。 让我们来看一个场景。

  • 创建对话框,然后依次创建其子级。 现在它处于上述第3点的状态。
  • 用户在列表框中选择一个项目,然后列表框向其父窗口发送一条消息,指示选择。
  • 对话框从其列表框接收消息,并将消息发送到其子文本框,以使所选项目文本成为当前内容。
  • 文本框接收此消息,并将其内容设置为消息中接收的文本。 然后,它向其父级发送一条消息,指示其内容已更改。
  • 对话框从其子文本框接收消息,指示其内容已更改。 然后,对话框将消息发送到“确定”按钮,通知其启用。
  • 用户单击“确定”,并且“按钮”会向其父窗口发送一条消息,指示已单击该消息。
  • 对话框向其客户端发送一条消息,指示已成功输入文本。

您可以在任意数量的可能场景中进行播放,并且只要DialogBox以此处所述的方式充当中介者,子组件就可以完美地协同工作,而无需了解它们的兄弟姐妹。

现在,如果您继续考虑每个组件-对话框; 文本框; 列表框; 确定按钮; 取消按钮-作为演员,他们可能类似于以下内容。

每个圆形对象都是一个演员。 演员之间的联系松散,孩子演员对他们的兄弟姐妹一无所知,只对他们的父母一无所知。 父DialogBox可以与其每个子级通信,并且每个子级可以与其父级通信。 所有通信均通过消息发送完成。

您是否从上述情况中注意到,在异步消息传递环境中操作组件没有引起混淆? 这些行为者并不关心其他行为者何时做事,只是在某些时候可能发生某些事件。 当这些事件确实发生时,它们将被发送到适当的参与者组件,并作为异步传递的消息被接收。 参与者必须只知道如何对收到的消息做出React,以及如何将消息发送给一个或多个其他组件参与者。 所有这些共同构成了一个非常健壮的设计,可以很好地扩展和执行。

我已经使用vlingo / actors工具箱实现了一个演员的示例,展示了上述消息传递行为。 我在这里没有提供所有示例代码。 您可以在GitHub上找到完整的源代码

public class SchemaSelectionDialog extends DialogBoxComponent {
  ...
  public void createSelf(final Specification specification) {
    super.createSelf(specification);
    text = createChild(Textbox.with(self, …, "text"));
    list = createChild(Listbox.with(self, …, "list"));
    ok = createChild(Button.with(self, "Ok", …, false, "ok"));
    cancel = createChild(Button.with(self, "Cancel", …, "cancel"));

    if (specification.hasParameters()) {
      list.items(specification.parameter(0));
    }
  }
  ...
}

在上方,您可以看到SchemaSelectionDialog,它是一个DialogBoxComponent。 不要太在意各种课程的细节。 名称应该有意义。 假定所有主要组件(例如对话框)都是参与者。 作为参与者,它们完全异步运行。

还请参见:

在处理createSelf()消息时,对话框将创建其子级,并且它们都是actor。 所有这些子组件都如上所述,一个文本框,一个列表框和两个Button控件。 请注意,“确定”按钮是在一个参数中带有错误标志的情况下创建的,表示默认情况下它是禁用的。 接下来考虑特定的调解员行为。 如您所料,每个Window(是的,Window是由所有GUI组件实现的基础协议)都将接收on(Event)消息。 只要其子控件之一发生任何变化,对话框就会收到这些消息。

public void on(final Event event) {
  ...
}

通过将各种事件类型分解为单独的消息,此功能可能会更好,但是也许您可以自己承担该任务来探索Actor模型。 这是一个提示和随附的文档

public class SchemaSelectionDialog
    extends DialogBoxComponent
   {
  ...
}

当选择列表框中的一个项目时,对话框会收到一个on(Event)消息。 如前所述,这通过将“列表框”中选定的项目文本放入“文本框”,使对话框能够调解预期的行为。

public void on(final Event event) {
  switch (event.type) {
  case "ItemSelected":
    handleList(event.typed());
    break;
  case "TextChanged":
    handleText(event.typed());
    break;
  case "Clicked":
    handleButton(event.typed());
    break;
   ...
   }
 }

选择一个项目时,列表框会将ItemSelected事件类型发送到父对话框。 此切换案例委托handleList(ItemSelected)进行中介,将所选项目文本放入文本框中,这正是它的作用。

private void handleList(final ItemSelected selected) {
  text.content(selected.content);
}

当文本框接收到content(String)消息时,它将以String为内容,然后将on(TextChanged)消息发送到其父级对话框。 您可以在该事件类型的切换案例的上方看到,该事件委托给handleText(TextChanged)。

private void handleText(final TextChanged changed) {
  if (!changed.content.isEmpty()) {
    list.select(changed.content);
    value = changed.content;
    ok.enable();
  } else {
    list.select(-1);
    value = "";
    ok.disable();
  }
}

handleText()方法测试是否存在内容。 如果存在文本内容,则会发生三件事:尝试选择与文本框文本匹配的列表框项,文本值保留在对话框状态中,并启用“确定”按钮。

但是选定的列表框文本不是刚放在文本框中吗? 好吧,我们不确定。 用户可能已经在文本框中输入了文本。 因此,如果已经选择了相同的项目,则列表框必须忽略select(String)消息,否则实际上将出现无尽的冗余消息(不是一件好事)。

另一方面,如果“文本框”的内容为空,则必须发生三件事:向列表框发送一条select(-1)消息,该消息导致对所有选定项的取消选择,值状态设置为空字符串,并且确定按钮被禁用。

收到on(Clicked)消息后,将使用handleButton(Clicked)行为。

private void handleButton(final Clicked clicked) {
  final Result result = clicked.tag.equals("ok") ?
        Result.SUCCEEDED : Result.CANCELLED;
  final WindowInfo info = selfWindowInfo();
  info.parent.on(new Completed(self, info.id, info.tag,
                  clicked.content, result, value));
}

handleButton(Click)方法将成功或取消完成对话框。 检查事件以查看单击了哪个事件(确定或取消),并使用了相应的结果。 之后,对话框将on(Completed)消息发送到其父窗口。

从该示例中可以学到更多的经验教训,我欢迎您来看看并进行实验。 这种方法提供了熟悉的概念,可以肯定,您一定会从中受益!

请参阅以下有用的资源。

代码: https //github.com/vlingo
文档: docs.vlingo.io

开源React式vlingo /平台代码和文档。

翻译自: https://jaxenter.com/actors-reactive-programming-159940.html

演员网站

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值