Robotlegs AS3第二部分:模型入门介绍
2010-09-25 10:27
441 查看
Adobe Flash Builder 4 简体中文正式版 Windows版点击下载:http://g.csdn.net/5134151
Adobe Flash Builder 4 简体中文正式版 Mac版点击下载
:http://g.csdn.net/5134152
Adobe 在线课堂:http://adobev.csdn.net/zx/index.html
Adobe平台技术峰会课程视频:http://adobev.csdn.net/
这是InsideRIA
上关于R
obotlegs AS3
入门介绍系列文章的第二部分。在第一部分,我们了解了何为Robotlegs AS3
,并且简要介绍了Robotlegs
的Context
(上下文)与Mediators
(媒介)。本文将继续阐述这些概念,并介绍相关模型。
如果你错过了第一部分,请看Robotlegs AS3
入门介绍--
第一部分:Context
(上下文)与Mediators
(媒介)(Part One: Context and Mediators
)。
模型是什么?
模型类封装你的应用程序数据,提供API
读取和操作数据。你的程序中的其它类会通过该API
请求模型。当模型中的数据更新后,模型会派遣事件,而你的程序中的其它类会对这些事件予以反应。模型适合于抓取域逻辑,如执行计算或其它操作。有个例子就是购物车。向购物车模型添加了一个条目之后,购物车内新的商品总量会再次统计。新的总量被存储在模型里,供程序中的其它类读取。将这个逻辑置入你的模型里,确保不会“散落”在整个程序里,你就可以确切地知道哪里去查看你的数据是怎么样,在何时被操作了。
除了控制数据的读取外,模型还将保持程序的状态(state)
。状态(State
),就数据模型这个意义来说,和Flex State
并非同一个概念,这与控制程序的外观有关。当然,它们也是相关的,但是有了这个模型,就要考虑一系列对象。你想要跟踪选定的目标,所以数据模型有一个选择属性,随时根据选定的条目更新。程序的其它领域现在可以读取这个属性,查看哪个条目被选定,然后做出相应的反应。
模型可编写成便携式的。就如同你要牢记Services
(服务)一样,在开发模型时,你也要记住这点。有许多常见的数据组,可以轻松在一个程序和下一个之间传输。譬如,UserLoginModel
或者ShoppingCartModel
。让模型具有编写性,也不过是多花费些时间和精力,但是也就像为每个项目重复编写一次代码差不多。
模型的确值得你更多的注意力。它是你的程序的核心。大家总是惊叹于这些视觉组件。但是作为一个开发人员,你知道,数据才是真正最为重要的。这就是我们的任务,作为开发人员的任务:创建数据,精确传送到那些美丽的界面。这就是为什么在模型中隔离域逻辑非常重要。通过隔离,你就可以更轻松地定位,更新和维护数据了。对模型进行了基本的定义后,我们来看看一个小例子。
看看代码!
这个纯粹的 AS3
程序利用的是Keith Peters
出色的Minimal Comps
库。不要担心,如果你喜欢Flex (
你怎么会不喜欢呢?)
, 下一个例子就是一个Flex
程序。不过有了Minimal Comps
库,就可以很快地使用AS3
举出例子;而Robotlegs
和Flex
一样,使用起来很轻松。所以,我们来看看程序的具体内容吧。
SimpleListExample.zip
上面是一个我们将要检查的程序。这是一个简单的作者列表,选定的作者会有一段引言展示。这是一个归档的Flash Builder
项目 (zip 168k),
包括Robotlegs 1.1
和MinimalComps SWC
文件。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
= StageScaleMode.NO_SCALE;
}
}
这是程序的主要文件,进入点。这是个简单的Sprite
。是Robotlegs
程序。所以我们需要做的第一件事就是创建一个Context:
(上下文)。
SimpleListExampleContext.as
public
class
SimpleListExampleContext
extends
Context
{
public
function
SimpleListExampleContext(contextView:DisplayObjectContainer)
{
super
(contextView);
}
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView, ListViewMediator);
mediatorMap.mapView(QuoteTextArea,
QuoteTextAreaMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
}
在Flex
程序中,通常会完全省略构造函数,因为在MXML
声明内,设定了contextView
。在Actionscript
程序中,你将contextView
传入构造函数中,这样可以立即设定。现在,我们在主application view
中创建一个SimpleListExampleContext
的实例。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
public
var
context:SimpleListExampleContext;
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
= StageScaleMode.NO_SCALE;
context =
new
SimpleListExampleContext(
this
);
}
}
你应该注意到上下文变量。必须有一个上下文的参考,这点很重要。如果你只是在构造函数里创建一个SimpleListExampleContext
的新实例,而不将它放入变量,那它就是一个收集在Flash Players
上的无用“垃圾”。这会导致一些麻烦,需要花费时间认真处理!有了Flex,
你只需在MXML
(紧跟参照,而无需变量)中声明上下文,除非你在Script
tag
中创建了上下文。它将要求一个参照,正如上面给出的Actionscript
范例。
程序有两个视图。可以选定一个名称表,而文本区域会显示列表中选定条目的quote
。这些视图为:
l
ListView
l
QuoteTextArea
命名方案倒还有创意。这两个视图就是基础Minimal
Comps
类的次类。它们是:
ListView.as
public
class
ListView
extends
List
{
public
function
ListView(parent:DisplayObjectContainer)
{
super
(parent);
}
}
QuoteTextArea.as
public
class
QuoteTextArea
extends
TextArea
{
public
function
QuoteTextArea(parent:DisplayObjectContainer)
{
super
(parent);
}
}
这个程序只有其中的一个。如果我们只是使用基础列表和TextArea
类,功能性就非常强。为什么都是使用次类?这是一个好习惯,尤其当处理依赖注入时。如果我们知道,我们将要协调一个视图类,将它加入次类,然后根据其目的进行命名。这么做时,很容易就隔离开,以进行协调。
现在,我们需要做的就是,将这两个视图作为主程序的子程序放入stage
上。在
Actionscript
程序中,我倾向于将createChildren
方法放在主视图上,然后从mediator
中调用。下面是才采用createChildren
方法的主视图。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
private
var
hbox:HBox;
private
var
list
:ListView;
private
var
quoteText:QuoteTextArea;
public
var
context:SimpleListExampleContext;
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
=
StageScaleMode.NO_SCALE;
context =
new
SimpleListExampleContext(
this
);
}
/**
* Called from ApplicationMediator's
onRegister()
*/
public
function
createChildren():
void
{
hbox =
new
HBox(
this
,0,0);
addChild(hbox);
list
=
new
ListView(hbox);
list
.alternateRows =
true
;
quoteText =
new
QuoteTextArea(hbox);
quoteText.editable =
false
;
quoteText.
selectable
=
false
;
}
}
你可能会想,为什么不直接在构造函数中添加视图?我倾向于在添加子程序之前,启动Robotlegs
。从ApplicationMediator
中调用createChildren()
,我们可以百分百地确定所有的初始应用bootstrapping
已经完成,准备完毕。下面是ApplicationMediator:
ApplicationMediator.as
public
class
ApplicationMediator
extends
Mediator
{
[Inject]
public
var
view:SimpleListExample;
override
public
function
onRegister():
void
{
view.createChildren();
}
}
在本例中,mediator
只有一个任务,但是在你的程序中,协调视图(contextView
)是个轻便的机制。Mediator
被创建之后,需要被映射。这一步很简单,也容易被遗漏,但是当你遇到bug
,而你的mediator
不予反应时,你就会想起来。很有可能发生的情况就是;它没有被映射,或者它的视图组件不是ADDED_TO_STAGE
。在你的上下文中,启动的方法如下所示:
SimpleListExampleContext.as
override
public
function
startup():
void
{
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
当你现在运行程序时,你应该看到一个空列表和文本区域。现在,我们需要获取一些数据视图。我们将在模型类里放入一些静态数据,而我们的视图组件的mediator
可以读取。下面是基本的模型:
AuthorModel.as
public
class
AuthorModel
extends
Actor
{
private
var
_list:
Array
;
public
function
get
list
():
Array
{
if
(!_list)
initializeList();
return
_list;
}
protected
function
initializeList():
void
{
var
twain:Author =
new
Author("
Twain
");
var
poe:Author =
new
Author("
Poe
");
var
plato:Author =
new
Author("
Plato
");
var
fowler:Author =
new
Author("
Fowler
");
twain.quote = "
Why, I have known clergymen,
good men, kind-hearted, liberal, sincere
" +
"
, and all that, who did not
know the meaning of a 'flush.' It is enough
" +
"
to make one ashamed of one's
species.
";
fowler.quote = "
Any fool can write code that
a computer can understand.
" +
"
Good programmers write code
that humans can understand.
";
poe.quote = "
Deep into that darkness
peering, long I stood there, wondering,
" +
"
fearing, doubting, dreaming
dreams no mortal ever dared to dream before.
";
plato.quote = "
All things will be produced
in superior quantity and quality, and with greater ease,
" +
"
when each man works at a
single occupation, in accordance with his natural gifts,
" +
"
and at the right moment,
without meddling with anything else.
";
_list =
[twain,fowler,poe,plato];
}
}
你马上会注意到AuthorModel
拓展 Actor
。Actor
是一个配有MVCS
的便捷类。它提供了恰当的代码,用于注入用来在上下文中沟通的IEventDispatcher
,及通过该调度程序发送时间的dispatch()
方法。不一定要拓展Actor,
但是如果不拓展的话,你就需要亲自提供IEventDispatcher
注入点。Robotlegs MVC+S
中的模型是纯粹概念性的。没有模型类可拓展,命名规则不过是用来表述类的意图。
模型现在提供一个我欣赏的作者列表,并附有每位作者的一段引言。从下面可以看出,作者类是一个可以保存这些属性的简单的价值对象:
Author.as
public
class
Author
{
public
var
name
:
String
;
public
var
quote:
String
;
public
function
Author(
name
:
String
)
{
this
.
name
=
name
;
}
/**
* Minimal comps took issue with toString();
* @return
*
*/
public
function
get
label
():
String
{
return
name
;
}
}
当模型中充满数据时,我们需要向列表传递数据,以供展示。第一步就是,映射模型,进行注入。第二步就是协调ListView
,将数据从模型转移到列表。你的上下文的startup()
方法,在模型映射之后,会如下所示;
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
为了映射模型,或者其它你想要诸如的类,你将使用上下文的注入器。注入器有几个方法用于映射类和值。mapSingleton()
方法是常用来为注入而映射简单类的方法。应该注意到,在该上下文中,“singleton
”不是指的设计模式中严格意义上的Singleton
。在本例中,mapSingleton()
意味着只要有要求,注入器将创建,并提供AuthorModel
的单一实例。如果你想要的话,你可以有任意个AuthorModel
实例,但是注入器只会创建,并注入你使用上述映射要求的那一个。还有其它几个方法可使用注入器进行映射,我强烈推荐您读一读Till Schneideriet
关于SwiftSuspenders Injector
的文章。在缺省状态下,这就是Robotlegs
使用的。Robotlegs
最佳实践(Robotlegs Best Practices
)也讨论了使用注入器。此外,我们还将讨论其它注入映射选择。
有了用于注入的,已被映射的模型,我们就可以进一步将作者放入他们的列表。为此,我们将协调ListView
,将 AuthorModel
注入 mediator
中。下面是ListView
的mediator
:
ListViewMediator.as
public
class
ListViewMediator
extends
Mediator
{
[Inject]
public
var
view:ListView;
[Inject]
public
var
authorModel:AuthorModel;
override
public
function
onRegister():
void
{
view.items = authorModel.
list
;
}
}
在协调的视图组件 [Inject]
标签外,我们没有看[Inject]
标签的使用,也没有讨论Robotlegs
如何提供读取你的类的依赖注入方法。在ListViewMediator
中,你会看到视图被注入。除了视图外,还有一个公共属性,属于类型AuthorModel
的AuthorModel
,标识有[Inject]
标签。当你在公共属性上放置[Inject]
标签,Robotlegs
创建类时,它将根据你映射的规则“注入”该属性。注意,如果你没有为注入提供规则,你会收到一个运行时间错误,将你指向问题所在。如果这种情况发生,确保捡查映射。在本例中,我们还使用了mapSingleton()
,以让AuthorModel
为注入做好准备。
当mediator
被完整地构架,并且提供注入,使用运行的mediator
的onRegister()
方法,我们读取模型,并且将列表属性赋值到视图的条目属性。真棒!我们现在应该看看列表中的条目。
...
好...
...
真棒!...
首先,我们需要映射mediator
:
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView,
ListViewMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
这就对了。ListView
被协调。记住映射的次序。ListView mediator
映射在SimpleListExample (
主图)
映射之上。SimpleListExample
是主图,正如 contextView
。当contextView
的类被映射时,它的处理略有不同。contextView
马上被协调,而不是监听ADDED_TO_STAGE
事件的发生。鉴于contextView
已经出现,我们不能坚持监听可能不会发生的事件。因为我们想要ListView
被添加时,进行协调,我们要确保它在ApplicationMediators onRegister()
有机会被调用前被映射。如果你再次调用,就是在ApplicationMediator's onRegister()
这里,我们将要通知主视图添加子集,包括 ListView
。
所以,当ListView
被填充满数据,你现在可以从列表中的作者列表中进行选择了。非常激动吧?稍微控制下自己吧。不过还有步骤要继续。现在,我们想要用一些文本填充QuoteTextArea
,最好是选定作者的引言。为此,我们将要向AuthorModel
做一些添加,以跟综选定的作者。当作者在ListView
内选定,ListViewMediator
将更新AuthorModel
。AuthorModel
然后发送事件,通知任何可能任何可能正在监听的人,作者被选定。我们还需要为QuoteTextArea
创建一个mediator
,这样就可以监听该事件,并且根据选定作者的引言予以更新。我们知道我们会需要该事件,所以首先;
SelectedAuthorEvent.as
public
class
SelectedAuthorEvent
extends
Event
{
public
static
const SELECTED:
String
= "
authorSelected
";
private
var
_author:Author;
public
function
get
author():Author
{
return
_author;
}
public
function
SelectedAuthorEvent(
type
:
String
, author:Author =
null
, bubbles:
Boolean
=
false
, cancelable:
Boolean
=
false
)
{
super
(
type
, bubbles, cancelable);
_author = author;
}
override
public
function
clone():Event
{
return
new
SelectedAuthorEvent(
type
, author, bubbles,
cancelable)
}
}
该事件并不引人注意。它就是个典型的定制事件,有一个常量,SELECTED
,用于可选择的作者参数。鉴于我们已经有了该事件,我们需要更新AuthorModel
,跟综选定的作者,当出现更改时,通知程序。
AuthorModel.as
private
var
_selected:Author;
public
function
get
selected():Author
{
return
_selected;
}
public
function
set
selected(value:Author):
void
{
_selected = value;
dispatch(
new
SelectedAuthorEvent(SelectedAuthorEvent.SELECTED, selected));
}
有了添加到AuthorModel
的代码(如上所示),我们能够有效地跟综现在选定的作者。为了在该模型上设定该属性,我们将更新ListViewMediator
,为ListView
选定的事件进行监听,并适时更新模型。
ListViewMediator.as
override
public
function
onRegister():
void
{
view.items = authorModel.
list
;
addViewListener(Event.SELECT,
handleSelected)
}
private
function
handleSelected(event:Event):
void
{
authorModel.selected = view.selectedItem as
Author;
}
在ListViewMediator's
onRegister()
里面,我们将使用addViewListener()
方法,在视图上添加一个事件监听器,使用handleSelected
方法处理。现在,当列表中的条目被选定后,事件处理器方法会读取authorModel
选定的属性,并且使用选定的条目进行更新。设定该值,然后AuthorModel
会派遣事件,通知程序其它部分已经发生的内容。
“为什么不在这里派遣选定事件,然后执行呢?”
你也可以这样,如果你的程序很简单的话,这样做也是一个恰当的方法。但是我没有遇到很多这么简单的程序,这就是如何使用Model
的一个范例。因此,我们需要做的工作还很多。鉴于我们已经开始了这个操作,我们还需要将该文本添加到QuoteTextArea,
这样可以进行协调。
QuoteTextAreaMediator.as
public
class
QuoteTextAreaMediator
extends
Mediator
{
[Inject]
public
var
view:QuoteTextArea;
override
public
function
onRegister():
void
{
addContextListener(SelectedAuthorEvent.SELECTED,
handleSelectedAuthorChanged)
}
private
function
handleSelectedAuthorChanged(event:SelectedAuthorEvent):
void
{
var
author:Author = event.author;
view.
text
= author.quote;
}
}
就是这样了。QuoteTextArea
现在与程序其它部分连接起来。在它的onRegister
里面,我们将使用addContextListener()
为SelectedAuthorEvent.SELECTED
进行监听,使用with
handleSelectedAuthorChanged
进行处理。
handleSelectedAuthorChanged
方法从事件中提取信息,更新视图的文本属性(使用选定作者的引言)。此后,我们获得被映射的mediator
,我们将实现本范例的功能性的深度。
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView,
ListViewMediator);
mediatorMap.mapView(QuoteTextArea, QuoteTextAreaMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
有了这个,你就有了范例,该范例包括了在Robotlegs
程序中使用Model
的基本条件。作为数据的护卫,模型在你的程序中发挥了非常重要的作用。利用模型作为数据的读取点,你在数据存储和操作的位置隔离。当你坐下来解决一个问题时,你知道在哪里找关于数据的内容及随后程序状态的显示。如果你的数据散落在程序中,就很难快速隔离问题点,或者给程序添加功能。
一篇博文简要介绍了模型。我强烈推荐对MVC
中的M
进行研究。在下一个范例中,我们来看看服务,并且看看在Robotlegs
程序中如何使用它们。在服务之后,我们会查看Commands
,以在讨论下一步课题之前,完成Robotlegs MVC+S
的执行。
如果你不能等,在我的博客上(还有互联网的其它网站)有一些文章都是讨论的Robotlegs
,包括这个25
分钟的视频。John Lindquist
在他的博客上有个 Hello World
视频。此外,还有一个最佳操作文件,对很多人都大有裨益。你可以点击Robotlegs
知识库( Robotlegs Knowledge Base
)获取帮助和支持。它拥有大批活跃的社区志愿者,包括我自己。志愿者们都很乐于回答有关Robotlegs
的任何问题。此外,我还参与编写了马上要发表的Flex 4 in Action
,这本书有22
页专门讨论 Robotlegs
。
本文译自:http://insideria.com/2010/06/an-introduction-to-robotlegs-a-1.html
Adobe Flash Builder 4 简体中文正式版 Mac版点击下载
:http://g.csdn.net/5134152
Adobe 在线课堂:http://adobev.csdn.net/zx/index.html
Adobe平台技术峰会课程视频:http://adobev.csdn.net/
这是InsideRIA
上关于R
obotlegs AS3
入门介绍系列文章的第二部分。在第一部分,我们了解了何为Robotlegs AS3
,并且简要介绍了Robotlegs
的Context
(上下文)与Mediators
(媒介)。本文将继续阐述这些概念,并介绍相关模型。
如果你错过了第一部分,请看Robotlegs AS3
入门介绍--
第一部分:Context
(上下文)与Mediators
(媒介)(Part One: Context and Mediators
)。
模型是什么?
模型类封装你的应用程序数据,提供API
读取和操作数据。你的程序中的其它类会通过该API
请求模型。当模型中的数据更新后,模型会派遣事件,而你的程序中的其它类会对这些事件予以反应。模型适合于抓取域逻辑,如执行计算或其它操作。有个例子就是购物车。向购物车模型添加了一个条目之后,购物车内新的商品总量会再次统计。新的总量被存储在模型里,供程序中的其它类读取。将这个逻辑置入你的模型里,确保不会“散落”在整个程序里,你就可以确切地知道哪里去查看你的数据是怎么样,在何时被操作了。
除了控制数据的读取外,模型还将保持程序的状态(state)
。状态(State
),就数据模型这个意义来说,和Flex State
并非同一个概念,这与控制程序的外观有关。当然,它们也是相关的,但是有了这个模型,就要考虑一系列对象。你想要跟踪选定的目标,所以数据模型有一个选择属性,随时根据选定的条目更新。程序的其它领域现在可以读取这个属性,查看哪个条目被选定,然后做出相应的反应。
模型可编写成便携式的。就如同你要牢记Services
(服务)一样,在开发模型时,你也要记住这点。有许多常见的数据组,可以轻松在一个程序和下一个之间传输。譬如,UserLoginModel
或者ShoppingCartModel
。让模型具有编写性,也不过是多花费些时间和精力,但是也就像为每个项目重复编写一次代码差不多。
模型的确值得你更多的注意力。它是你的程序的核心。大家总是惊叹于这些视觉组件。但是作为一个开发人员,你知道,数据才是真正最为重要的。这就是我们的任务,作为开发人员的任务:创建数据,精确传送到那些美丽的界面。这就是为什么在模型中隔离域逻辑非常重要。通过隔离,你就可以更轻松地定位,更新和维护数据了。对模型进行了基本的定义后,我们来看看一个小例子。
看看代码!
这个纯粹的 AS3
程序利用的是Keith Peters
出色的Minimal Comps
库。不要担心,如果你喜欢Flex (
你怎么会不喜欢呢?)
, 下一个例子就是一个Flex
程序。不过有了Minimal Comps
库,就可以很快地使用AS3
举出例子;而Robotlegs
和Flex
一样,使用起来很轻松。所以,我们来看看程序的具体内容吧。
SimpleListExample.zip
上面是一个我们将要检查的程序。这是一个简单的作者列表,选定的作者会有一段引言展示。这是一个归档的Flash Builder
项目 (zip 168k),
包括Robotlegs 1.1
和MinimalComps SWC
文件。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
= StageScaleMode.NO_SCALE;
}
}
这是程序的主要文件,进入点。这是个简单的Sprite
。是Robotlegs
程序。所以我们需要做的第一件事就是创建一个Context:
(上下文)。
SimpleListExampleContext.as
public
class
SimpleListExampleContext
extends
Context
{
public
function
SimpleListExampleContext(contextView:DisplayObjectContainer)
{
super
(contextView);
}
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView, ListViewMediator);
mediatorMap.mapView(QuoteTextArea,
QuoteTextAreaMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
}
在Flex
程序中,通常会完全省略构造函数,因为在MXML
声明内,设定了contextView
。在Actionscript
程序中,你将contextView
传入构造函数中,这样可以立即设定。现在,我们在主application view
中创建一个SimpleListExampleContext
的实例。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
public
var
context:SimpleListExampleContext;
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
= StageScaleMode.NO_SCALE;
context =
new
SimpleListExampleContext(
this
);
}
}
你应该注意到上下文变量。必须有一个上下文的参考,这点很重要。如果你只是在构造函数里创建一个SimpleListExampleContext
的新实例,而不将它放入变量,那它就是一个收集在Flash Players
上的无用“垃圾”。这会导致一些麻烦,需要花费时间认真处理!有了Flex,
你只需在MXML
(紧跟参照,而无需变量)中声明上下文,除非你在Script
tag
中创建了上下文。它将要求一个参照,正如上面给出的Actionscript
范例。
程序有两个视图。可以选定一个名称表,而文本区域会显示列表中选定条目的quote
。这些视图为:
l
ListView
l
QuoteTextArea
命名方案倒还有创意。这两个视图就是基础Minimal
Comps
类的次类。它们是:
ListView.as
public
class
ListView
extends
List
{
public
function
ListView(parent:DisplayObjectContainer)
{
super
(parent);
}
}
QuoteTextArea.as
public
class
QuoteTextArea
extends
TextArea
{
public
function
QuoteTextArea(parent:DisplayObjectContainer)
{
super
(parent);
}
}
这个程序只有其中的一个。如果我们只是使用基础列表和TextArea
类,功能性就非常强。为什么都是使用次类?这是一个好习惯,尤其当处理依赖注入时。如果我们知道,我们将要协调一个视图类,将它加入次类,然后根据其目的进行命名。这么做时,很容易就隔离开,以进行协调。
现在,我们需要做的就是,将这两个视图作为主程序的子程序放入stage
上。在
Actionscript
程序中,我倾向于将createChildren
方法放在主视图上,然后从mediator
中调用。下面是才采用createChildren
方法的主视图。
SimpleListExample.as
public
class
SimpleListExample
extends
Sprite
{
private
var
hbox:HBox;
private
var
list
:ListView;
private
var
quoteText:QuoteTextArea;
public
var
context:SimpleListExampleContext;
public
function
SimpleListExample()
{
stage.
align
= StageAlign.TOP_LEFT;
stage.
scaleMode
=
StageScaleMode.NO_SCALE;
context =
new
SimpleListExampleContext(
this
);
}
/**
* Called from ApplicationMediator's
onRegister()
*/
public
function
createChildren():
void
{
hbox =
new
HBox(
this
,0,0);
addChild(hbox);
list
=
new
ListView(hbox);
list
.alternateRows =
true
;
quoteText =
new
QuoteTextArea(hbox);
quoteText.editable =
false
;
quoteText.
selectable
=
false
;
}
}
你可能会想,为什么不直接在构造函数中添加视图?我倾向于在添加子程序之前,启动Robotlegs
。从ApplicationMediator
中调用createChildren()
,我们可以百分百地确定所有的初始应用bootstrapping
已经完成,准备完毕。下面是ApplicationMediator:
ApplicationMediator.as
public
class
ApplicationMediator
extends
Mediator
{
[Inject]
public
var
view:SimpleListExample;
override
public
function
onRegister():
void
{
view.createChildren();
}
}
在本例中,mediator
只有一个任务,但是在你的程序中,协调视图(contextView
)是个轻便的机制。Mediator
被创建之后,需要被映射。这一步很简单,也容易被遗漏,但是当你遇到bug
,而你的mediator
不予反应时,你就会想起来。很有可能发生的情况就是;它没有被映射,或者它的视图组件不是ADDED_TO_STAGE
。在你的上下文中,启动的方法如下所示:
SimpleListExampleContext.as
override
public
function
startup():
void
{
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
当你现在运行程序时,你应该看到一个空列表和文本区域。现在,我们需要获取一些数据视图。我们将在模型类里放入一些静态数据,而我们的视图组件的mediator
可以读取。下面是基本的模型:
AuthorModel.as
public
class
AuthorModel
extends
Actor
{
private
var
_list:
Array
;
public
function
get
list
():
Array
{
if
(!_list)
initializeList();
return
_list;
}
protected
function
initializeList():
void
{
var
twain:Author =
new
Author("
Twain
");
var
poe:Author =
new
Author("
Poe
");
var
plato:Author =
new
Author("
Plato
");
var
fowler:Author =
new
Author("
Fowler
");
twain.quote = "
Why, I have known clergymen,
good men, kind-hearted, liberal, sincere
" +
"
, and all that, who did not
know the meaning of a 'flush.' It is enough
" +
"
to make one ashamed of one's
species.
";
fowler.quote = "
Any fool can write code that
a computer can understand.
" +
"
Good programmers write code
that humans can understand.
";
poe.quote = "
Deep into that darkness
peering, long I stood there, wondering,
" +
"
fearing, doubting, dreaming
dreams no mortal ever dared to dream before.
";
plato.quote = "
All things will be produced
in superior quantity and quality, and with greater ease,
" +
"
when each man works at a
single occupation, in accordance with his natural gifts,
" +
"
and at the right moment,
without meddling with anything else.
";
_list =
[twain,fowler,poe,plato];
}
}
你马上会注意到AuthorModel
拓展 Actor
。Actor
是一个配有MVCS
的便捷类。它提供了恰当的代码,用于注入用来在上下文中沟通的IEventDispatcher
,及通过该调度程序发送时间的dispatch()
方法。不一定要拓展Actor,
但是如果不拓展的话,你就需要亲自提供IEventDispatcher
注入点。Robotlegs MVC+S
中的模型是纯粹概念性的。没有模型类可拓展,命名规则不过是用来表述类的意图。
模型现在提供一个我欣赏的作者列表,并附有每位作者的一段引言。从下面可以看出,作者类是一个可以保存这些属性的简单的价值对象:
Author.as
public
class
Author
{
public
var
name
:
String
;
public
var
quote:
String
;
public
function
Author(
name
:
String
)
{
this
.
name
=
name
;
}
/**
* Minimal comps took issue with toString();
* @return
*
*/
public
function
get
label
():
String
{
return
name
;
}
}
当模型中充满数据时,我们需要向列表传递数据,以供展示。第一步就是,映射模型,进行注入。第二步就是协调ListView
,将数据从模型转移到列表。你的上下文的startup()
方法,在模型映射之后,会如下所示;
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
为了映射模型,或者其它你想要诸如的类,你将使用上下文的注入器。注入器有几个方法用于映射类和值。mapSingleton()
方法是常用来为注入而映射简单类的方法。应该注意到,在该上下文中,“singleton
”不是指的设计模式中严格意义上的Singleton
。在本例中,mapSingleton()
意味着只要有要求,注入器将创建,并提供AuthorModel
的单一实例。如果你想要的话,你可以有任意个AuthorModel
实例,但是注入器只会创建,并注入你使用上述映射要求的那一个。还有其它几个方法可使用注入器进行映射,我强烈推荐您读一读Till Schneideriet
关于SwiftSuspenders Injector
的文章。在缺省状态下,这就是Robotlegs
使用的。Robotlegs
最佳实践(Robotlegs Best Practices
)也讨论了使用注入器。此外,我们还将讨论其它注入映射选择。
有了用于注入的,已被映射的模型,我们就可以进一步将作者放入他们的列表。为此,我们将协调ListView
,将 AuthorModel
注入 mediator
中。下面是ListView
的mediator
:
ListViewMediator.as
public
class
ListViewMediator
extends
Mediator
{
[Inject]
public
var
view:ListView;
[Inject]
public
var
authorModel:AuthorModel;
override
public
function
onRegister():
void
{
view.items = authorModel.
list
;
}
}
在协调的视图组件 [Inject]
标签外,我们没有看[Inject]
标签的使用,也没有讨论Robotlegs
如何提供读取你的类的依赖注入方法。在ListViewMediator
中,你会看到视图被注入。除了视图外,还有一个公共属性,属于类型AuthorModel
的AuthorModel
,标识有[Inject]
标签。当你在公共属性上放置[Inject]
标签,Robotlegs
创建类时,它将根据你映射的规则“注入”该属性。注意,如果你没有为注入提供规则,你会收到一个运行时间错误,将你指向问题所在。如果这种情况发生,确保捡查映射。在本例中,我们还使用了mapSingleton()
,以让AuthorModel
为注入做好准备。
当mediator
被完整地构架,并且提供注入,使用运行的mediator
的onRegister()
方法,我们读取模型,并且将列表属性赋值到视图的条目属性。真棒!我们现在应该看看列表中的条目。
...
好...
...
真棒!...
首先,我们需要映射mediator
:
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView,
ListViewMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
这就对了。ListView
被协调。记住映射的次序。ListView mediator
映射在SimpleListExample (
主图)
映射之上。SimpleListExample
是主图,正如 contextView
。当contextView
的类被映射时,它的处理略有不同。contextView
马上被协调,而不是监听ADDED_TO_STAGE
事件的发生。鉴于contextView
已经出现,我们不能坚持监听可能不会发生的事件。因为我们想要ListView
被添加时,进行协调,我们要确保它在ApplicationMediators onRegister()
有机会被调用前被映射。如果你再次调用,就是在ApplicationMediator's onRegister()
这里,我们将要通知主视图添加子集,包括 ListView
。
所以,当ListView
被填充满数据,你现在可以从列表中的作者列表中进行选择了。非常激动吧?稍微控制下自己吧。不过还有步骤要继续。现在,我们想要用一些文本填充QuoteTextArea
,最好是选定作者的引言。为此,我们将要向AuthorModel
做一些添加,以跟综选定的作者。当作者在ListView
内选定,ListViewMediator
将更新AuthorModel
。AuthorModel
然后发送事件,通知任何可能任何可能正在监听的人,作者被选定。我们还需要为QuoteTextArea
创建一个mediator
,这样就可以监听该事件,并且根据选定作者的引言予以更新。我们知道我们会需要该事件,所以首先;
SelectedAuthorEvent.as
public
class
SelectedAuthorEvent
extends
Event
{
public
static
const SELECTED:
String
= "
authorSelected
";
private
var
_author:Author;
public
function
get
author():Author
{
return
_author;
}
public
function
SelectedAuthorEvent(
type
:
String
, author:Author =
null
, bubbles:
Boolean
=
false
, cancelable:
Boolean
=
false
)
{
super
(
type
, bubbles, cancelable);
_author = author;
}
override
public
function
clone():Event
{
return
new
SelectedAuthorEvent(
type
, author, bubbles,
cancelable)
}
}
该事件并不引人注意。它就是个典型的定制事件,有一个常量,SELECTED
,用于可选择的作者参数。鉴于我们已经有了该事件,我们需要更新AuthorModel
,跟综选定的作者,当出现更改时,通知程序。
AuthorModel.as
private
var
_selected:Author;
public
function
get
selected():Author
{
return
_selected;
}
public
function
set
selected(value:Author):
void
{
_selected = value;
dispatch(
new
SelectedAuthorEvent(SelectedAuthorEvent.SELECTED, selected));
}
有了添加到AuthorModel
的代码(如上所示),我们能够有效地跟综现在选定的作者。为了在该模型上设定该属性,我们将更新ListViewMediator
,为ListView
选定的事件进行监听,并适时更新模型。
ListViewMediator.as
override
public
function
onRegister():
void
{
view.items = authorModel.
list
;
addViewListener(Event.SELECT,
handleSelected)
}
private
function
handleSelected(event:Event):
void
{
authorModel.selected = view.selectedItem as
Author;
}
在ListViewMediator's
onRegister()
里面,我们将使用addViewListener()
方法,在视图上添加一个事件监听器,使用handleSelected
方法处理。现在,当列表中的条目被选定后,事件处理器方法会读取authorModel
选定的属性,并且使用选定的条目进行更新。设定该值,然后AuthorModel
会派遣事件,通知程序其它部分已经发生的内容。
“为什么不在这里派遣选定事件,然后执行呢?”
你也可以这样,如果你的程序很简单的话,这样做也是一个恰当的方法。但是我没有遇到很多这么简单的程序,这就是如何使用Model
的一个范例。因此,我们需要做的工作还很多。鉴于我们已经开始了这个操作,我们还需要将该文本添加到QuoteTextArea,
这样可以进行协调。
QuoteTextAreaMediator.as
public
class
QuoteTextAreaMediator
extends
Mediator
{
[Inject]
public
var
view:QuoteTextArea;
override
public
function
onRegister():
void
{
addContextListener(SelectedAuthorEvent.SELECTED,
handleSelectedAuthorChanged)
}
private
function
handleSelectedAuthorChanged(event:SelectedAuthorEvent):
void
{
var
author:Author = event.author;
view.
text
= author.quote;
}
}
就是这样了。QuoteTextArea
现在与程序其它部分连接起来。在它的onRegister
里面,我们将使用addContextListener()
为SelectedAuthorEvent.SELECTED
进行监听,使用with
handleSelectedAuthorChanged
进行处理。
handleSelectedAuthorChanged
方法从事件中提取信息,更新视图的文本属性(使用选定作者的引言)。此后,我们获得被映射的mediator
,我们将实现本范例的功能性的深度。
SimpleListExampleContext.as
override
public
function
startup():
void
{
injector.mapSingleton(AuthorModel);
mediatorMap.mapView(ListView,
ListViewMediator);
mediatorMap.mapView(QuoteTextArea, QuoteTextAreaMediator);
mediatorMap.mapView(SimpleListExample, ApplicationMediator);
}
有了这个,你就有了范例,该范例包括了在Robotlegs
程序中使用Model
的基本条件。作为数据的护卫,模型在你的程序中发挥了非常重要的作用。利用模型作为数据的读取点,你在数据存储和操作的位置隔离。当你坐下来解决一个问题时,你知道在哪里找关于数据的内容及随后程序状态的显示。如果你的数据散落在程序中,就很难快速隔离问题点,或者给程序添加功能。
一篇博文简要介绍了模型。我强烈推荐对MVC
中的M
进行研究。在下一个范例中,我们来看看服务,并且看看在Robotlegs
程序中如何使用它们。在服务之后,我们会查看Commands
,以在讨论下一步课题之前,完成Robotlegs MVC+S
的执行。
如果你不能等,在我的博客上(还有互联网的其它网站)有一些文章都是讨论的Robotlegs
,包括这个25
分钟的视频。John Lindquist
在他的博客上有个 Hello World
视频。此外,还有一个最佳操作文件,对很多人都大有裨益。你可以点击Robotlegs
知识库( Robotlegs Knowledge Base
)获取帮助和支持。它拥有大批活跃的社区志愿者,包括我自己。志愿者们都很乐于回答有关Robotlegs
的任何问题。此外,我还参与编写了马上要发表的Flex 4 in Action
,这本书有22
页专门讨论 Robotlegs
。
本文译自:http://insideria.com/2010/06/an-introduction-to-robotlegs-a-1.html
相关文章推荐
- Robotlegs AS3入门介绍 第二部分:Models(模型)
- Robotlegs AS3入门介绍--第三部分:Services(服务)
- MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第二部分)——IOrganizationService(一)
- 通过金矿模型介绍动态规划 (很好的动态规划入门介绍)
- RabbitMQ官方中文入门教程(PHP版) 第二部分:工作队列(Work queues)
- WMI 脚本入门:第二部分 (MSDN)
- 第二部分 Linux Shell高级编程技巧——第三章 运行级别脚本介绍
- 自组织神经网络介绍:自组织特征映射SOM(Self-organizing feature Map),第二部分
- 【第二部分-图像处理】第1章 Opencv图像处理入门
- Flash Player 10.1内部机制(第二部分)-执行模型之可变跑道
- WMI 脚本入门:第二部分 (MSDN)
- Macriomedia Flex入门教程第二部分――创建一个简单的计算器
- 自组织神经网络介绍:自组织特征映射SOM(Self-organizing feature Map),第二部分
- 最近邻算法和向量模型——第二部分——算法和数据结构
- [SearchEngine]《介绍 Nutch 第二部分:搜索》出来了
- Solarwinds 系列软件功能介绍(第二部分 配置和一致性管理)
- 【MyBatis框架】MyBatis入门程序第二部分
- MS CRM 2011的自定义和开发(10)——CRM web服务介绍(第二部分)——IOrganizationService(二)
- Android4开发入门经典 之 第二部分:Android应用的核心基础
- Xamarin.Forms跨平台开发入门-第二部分:深入解析