导读:
Using Namespaces to provide context in AS3December 17th, 2007
Namespacesin ActionScript 3 are particularly useful for providing context in an application. They also provide an added clarity to APIs outside of the typical language specific access modifiers.
AS3中的命名空间用来实现上下文特别有效,他们同时为某种语言规范之外的访问修饰提供了额外的清爽
For instance, let’s say we have an application which requires slightly different behaviors depending on a specific type of user. If the user is a guest, the application need only display a fairly basic view, however, if the user is an administrator the application must display a slightly more complex view.
比如说假设我们有个特别的应用程序,根据用户的不同类型呈现不同的行为,如果用户是客户,那么一个月程序只显示基本视图,如果用户是管理员,那么它要呈现稍复杂一点的界面
Based on the type of user we can deduce context and from this context we can provide a contextual namespace. The contextual namespace can then be utilized to invoke different methods with the same name on an object.
通过用户的类型我们可以推导出一个上下文,并根据此上下文我们提供一个命名空间的上下文,然后这个上下文就可以被用来唤醒对于同一个对象不同的方法
To help facilitate the management of a contextual namespace I have created a ContextNamespace API.
ContextNamespaceis a Singleton class which can be utilized to set and retrieve a contextual namespace based on context. Additionally, ContextNamespace implements INamespaceManagerwhich defines various convenience methods for retrieving information about a contextual namespace, comparing a Namespace against the contextual Namespace and comparing a URI against the contextual Namespace URI.
为了帮助环境上下文的管理我创建了上下文API,环境上下文命名空间是一个单件类,单件类可以被用来设置和获得环境特定上下文的上下文命名空间,特别的上下文命名空间实现了INamespaceManager此接口定义了一系列防爆的获得上下文空间的方法,将一个命名空间和一个上下文命名空间相比较以及将URI和环境上下文URI比较
Below is a simple example which demonstrates how to utilize the ContextNamespace API.
The class below utilizes two custom namespaces; admin and guest. Two methods with the same name are defined in the Class, each of which is under a different namespace.
下面是一个简单的例子用来展示如何使用如何使用这些API
package
{
importcom.domain.namespaces.admin
importcom.domain.namespaces.guest
publicclassUserViewHelper
{
// define the admin implementation of renderView
admin staticfunctionrenderView(): void
{
// admin implementation code…
}
// define the guest implementation of renderView
guest staticfunctionrenderView(): void
{
// guest implementation code…
}
}
}
To utilize ContextNamespace to retrieve a reference to the current contextual Namespace is simple.
importcom.ericfeminella.ns.ContextNamespace
// define a local namespace object
varns:Namespace;
// reference the contextual namespace
ns = ContextNamespace.instance.getNamespace()
// invoke methods using the namespace reference
// should the contextual namespace change the
// implementation will reflect the change
UserViewHelper.ns::renderView()
In the above code a local namespace is defined which references the current contextual namespace used by the application via ContextNamespace.instance.getNamespace(). The local reference is then used to identify the correct namespace from which methods are to be invoked.
在上面的代码中一个局部的命名空间定义来引用当前的上下文命名空间。通过调用,这个局部的引用然后就可以用来判断哪一个正确的调用应该执行
For additional examples which demonstrate how ContextNamespace can be utilized to provide a globally accessible reference to a namespace, view the ASDocs. 更多的例子可以参看帮助文档
AS3 Singletons, revisitedDecember 7th, 2007
The topic of Singletons in ActionScript 3.0 has been coming up again lately and it has been very interesting to see all of the unique solutions the community has come up with. In particular I like the idea of having Singleton metadatawhich would allow the compiler do all of the work for us.
单件的话题将会在后续的讨论中提到,单件可以帮助我们解决遇到的各种问题,我个人也很支持有一个单件的元标签这样就可以由计算机来帮我们完成所有的事情了
Personally I feel the Singleton patternis extremely useful. It is arguably one of the most common design patterns around today. Practically every management centric API requires a Singleton one way or another. Some developers claim that the Singleton pattern is nothing more than a euphemism for a global variable, to some extent this is true, however the intent of a Singleton is clearly different.
我个人觉得单件模式非常有用,它无疑是目前最常用到的设计模式之一,从应用的角度来说,每一个以管理为中心的API都需要一个或者多个单件,有些开发者称单件不过是个全局变量等等,某种程度上来讲有一定意义,但是单件的目的显然不只是全局变量
As useful as the Singleton pattern is my biggest complaint about Singletons has always been the actual construction code required to create / protect the Singleton instance. This extra code often becomes quite verbose and it is annoying to have to sift through all of the Singleton code when working with the actual class implementation code. It would also be nice to not have to constantly re-write the Singleton construction and implementation code every time a Singleton is needed.
虽然单件很有用但是我对单件最大的抱怨就是要手动产生单件的构造代码,这些额外重复的代码让人厌烦,因此最好是不要每一次编写一个单件模式的时候都要重新写一遍烦人的构造创建代码
So is there a way around all of this? Yes!
I developed a simple class called SingletonMonitor which singleton classes can extend to allow the omission of all Singleton specific construction code. All that is needed is to have the class which is to be a Singleton extend SingletonMonitor. That’s it. No more getInstance(), inner classes, type checking and so on is needed. As a best practice I recommend that you define the Singleton instance in the class itself in order to improve code readability.
有这样的事情吗?有!
我开发了一个简单的类称为单件监视器,这个类可以让所有的单件类都扩展来避免重复的代码,因此现在要做的便是从单件监视器来集成构建单件了,不再需要一遍又一遍的getInstance,类型检查等等
An example demonstrating how to use the SingletonMonitor can be seen in the following: 下面是一个演示类
package
{
publicclassManager extendsSingletonMonitor
{
// define the singleton instance of Manager
publicstaticconst instance:Manager = newManager()
}
}
As you can see no Singleton construction code is needed. Additionally, by extending SingletonMonitor you are clearly stating that the class is intended to be a Singleton.
So how is this accomplished? It’s pretty simple…
正如你所看见的,不需要任何的构建代码,只需要继承,那么是怎么完成的呢?也很简单
When a derived class is instantiated the SingletonMonitor constructor is invoked, the constructor parses the current stack trace in order to determine the derived class’ name (hence the hack). The name of the derived class is then used as a key in the SingletonMonitor hash table. When a subsequent instantiation of the class is made SingletonMonitor checks the name of the class and if it has previously been defined in the hash an exception is thrown. I originally developed this using introspection to determine the fully qualified name of the class, however the preferred implementation is to have the class eagerly instantiated at compiled time (i.e. constant), thus the stack trace is not available.
当一个继承类实例化的时候,单件监视器的构造函数被唤醒,构造函数解析当前的栈轨迹来解析集成类的名字,此名字作为监视器的哈希表的键,当一个此类实例化的时候,单件监视器检查类名字是否在此哈希表里,是否有异常抛出,我使用了内窥视技术来判断此类的完整名字,然而好一点的实现版本有更早的实例化时间,因此栈综不可获得
Admittedly this is a bit of a hack, but so are the alternatives, otherwise this issue would never have been a topic of discussion in the first place.
However what I like about this new approach is that the Singleton is being managed outside of it’s concrete implementation, and that is the goal of this post; to present an alternative means of managing Singleton construction. Through this the Singleton construction and management code can be omitted as it is being handled by a completely separate object.
有点像HACK但是其他的解决方案大抵也如此,要不然这个话题也不会成为标题栏的讨论帖,然而我所推崇的途径是单件在它具体的实现外被管理,这也是本帖的目标,提供另一种单件的构建方法,通过这,单件的创建和管理代码能够被完全解耦和出来由另外的一个对象负责
So the SingletonMonitor was the first example of how Singleton management can be achieved. The second example demonstrates the Singleton management approach implemented via composition as opposed to inheritance - which is my preferred mechanism of Singleton Management. In addition to creating the SingletonMonitor which utilizes inheritance I also created a SingletonManager which utilizes composition. The SingletonManager is the implementation I recommend and prefer.
单件监视器只是第一种途径,第二种途径是通过组合(反继承)这也是我推崇的单件管理方式,和单件监视器一样我也创建了一个单件管理器使用【组合】模式,这种实现方式我更喜欢,更推崇
An example demonstrating how to use the SingletonManager can be seen in the following: 一个例子
package
{
publicclassManager
{
// define the singleton instance of Manager
publicstaticconst instance:Manager = newManager()
// the constructor simply invokes SingletonManager
// validateInstance and passes a reference of the
// instance, that’s it.
publicfunctionManager()
{
SingletonManager.validateInstance(this)
}
}
}
The SingletonManager requires the class constructor to invoke SingletonManager.validateInstance and pass in a reference of the instance. This is automated in the SingletonMonitor as the class name is determined automatically which is convenient, however the readability of the SingletonManager is preferred as it clearly states intent. Additionally the SingletonManager guarantees the correct type is resolved.
构建管理器需要类构造函数来唤醒单件管理器,校验实例则传递此引用的实例,代码可读性很好,还有单件管理器保证了正确的类型被解析了。
So this is a new way of thinking about Singletons; to provide a management system from which Singleton construction and protection can consistently provided.
To be honest, this was really just an experiment I have been playing around with for some time now that I thought I should share, I am not sure if I would use the SingletonMonitor in production code as the parsing of the stack trace just feels a bit to much like a hack. However I will most likely utilize the SingeltonManager moving forward as it is a great way to abstract Singleton construction and protection from the class implementation.
这是一个新的看待单件的视角,通过一个管理系统将单件的管理和创建解耦和出来,老实说这其实是我的一个实验,我最近一直在思考,出结果了我觉得应该和大家分享。我不知道在实际的应用中我会不会用单件监视器来解析栈综,因为这有点像[HACK】但是我肯定会使用单件管理器来完成这样的一件事情
My hope is that there will be a true solution available as we move forward, but for the time being if you would like to create Singletons without the need for all of the Singleton implementation code feel free to extend SingletonMonitorfor management or SingletonManagerfor compositional management.
我希望是对于这个问题大家能够提出进一步的解决方案,你可以自由的扩充我所说到的这两种解决方案
IResponder and CairngormNovember 23rd, 2007
My original post on Cairngormand IResponderhad accidentally been deleted while updating my moderations queue, and many of you have contacted me stating that the post is no longer available so I will re-iterate what I mentioned in that post.
For some time now I have been entertaining the notion of abstracting IResponder implementations from Commandclasses into separate, discreet classes which are intended to handle asynchronous service invocation responses. There has been some talk in the Cairngorm community recently regarding Cairngorm Commands and IResponder implementations so I thought I would share my thoughts on the subject.
我考虑将abstracting IResponder 从commandclass模式转化为解耦和的单独的类已经有一段时间了,这个接口负责处理响应的异步服务调用,在CAIRNGORM社区里也有一些讨论,因此我想我应该把我的思考结果和大家共享
Typically most Cairngorm Eventsare handled by an associated Command. The Command handles the Event by updating a model on the ModelLocator, and / or instantiating a Business Delegate to manage invoking a middle-tier service.
通常CAIRNGORM事件将处理和特定的命令模式关联,命令模式通过根型模型定位器,或者实例化一个业务代表来唤醒一个中间件服务来处理事件
At this point one could argue that the Command has finished doing it’s job - handling the Event. Let’s clarify by taking a look at a formal definition of the Command Pattern:
到这个点上,有人称其实命令模式还没有完成它的任务,处理事件,让我们来看看命令模式的定义
“The Command pattern is a design pattern in which objects are used to represent actions. A command object encapsulates an action and its parameters.”
命令模式是指这样的模式,在这里对象用来代表相应的事件,一个事件对象封装了过程以及相应的参数
From this we can deduce (in the context of a Cairngorm Event) that the Event is the “action” and the Command is the object which encapsulates the handling of the Event (action). The actual handling of the Service response could be considered a separate concern which is outside of the direct concern of the Event and Command, thus requiring an additional object to handle the service response.
从这里我们可以获悉,事件是任务,而命令模式则是封装了相应的事件处理程序的对象,实际的服务响应处理可以视为是事件和命令模式之外的对象,因此需要额外的对象来处理服务响应
However for many developers it is (by design) typical to simply have the Command implement IResponder and also handle the response from the service in addition to the actual Event. This makes sense from a convenience perspective, but not necessarily from a design perspective.
但是还是有许多的开发者(设计者)特别将命令模式来作为响应接口的设计模式,这从方便的角度来说行的通,但是从设计的角度来讲行不通
What I have been experimenting with is pretty simple and straightforward. It involves having a completely separate object implement IResponder and handle the service response directly.
Consider the following example in which a specific use-case requires an account log in. The following classes would be required: LoginEvent, LoginCommand, LoginResponder and LoginDelegate. Utilizing a separate class as the responder is very simple and straightforward and would be implemented as follows:
我在实验的东西也很简单明了,它包含了一个完全分离的对象来实现IResponder 并且直接的处理响应,考虑下面的例子,登录用例,需要用到一下的类LoginEvent, LoginCommand, LoginResponder and LoginDelegate. ,使用一个完全分离的对象来实现IResponder很简单也只白,如:
package events
{
importcom.adobe.cairngorm.events.CairngormEvent
importvo.LoginVO
publicclassLoginEvent extendsCairngormEvent
{
publicstaticconst LOGIN_EVENT:String="LoginEvent"
publicvarvo:LoginVO;
publicfunctionLoginEvent(vo:LoginVO)
{
super(LOGIN_EVENT )
this.vo= vo;
}
}
}
So far nothing different here, the above Event is just like any other CairngormEvent. Now let’s take a look at the Command implementation.
看起来没什么区别,上面的事件就像其他的CairngormEvent,下面我们来看看命令模式的实现
package commands
{
importcom.adobe.cairngorm.commands.ICommand
importcom.adobe.cairngorm.events.CairngormEvent
importevents.LoginEvent
publicclassLoginCommand implementsICommand
{
publicfunctionexecute(event:CairngormEvent)
{
varevt:LoginEvent = event as LoginEvent;
varre:IResponder = newLoginResponder()
vardelegate:LoginDelegate = newLoginDelegate(re)
delegate.login(evt.vo.username, evt.vo.password)
}
}
}
Based on the above example, the only method which must be implemented is execute(), as defined by ICommand. The body of the execute() implementation instantiates an instance of LoginResponder and LoginDelegate, the LoginResponder instance is passed to the LoginDelegate as the IResponder instance.
As can be seen in the following example, the Business Delegate implementation is the same as any other typical Cairngorm Delegate:
package business
{
importcom.adobe.cairngorm.business.ServiceLocator
importmx.rpc.AsyncToken
importmx.rpc.IResponder
importmx.rpc.http.HTTPService
importvo.LoginVO
publicclassLoginDelegate
{
privatevarresponder:IResponder;
privatevarservice:HTTPService;
publicfunctionLoginDelegate(responder:IResponder)
{
this.responder= responder;
varsl:ServiceLocator = ServiceLocator.getInstance()
service = sl.getHTTPService(Services.LOGIN_SERVICE)
}
publicfunctionLogin(vo:LoginVO): void
{
varcall:AsyncToken=service.send(vo.username,vo.password)
call.addResponder(responder )
}
}
}
The IResponder implementation would be as follows:
package responders
{
importmx.rpc.IResponder
publicclassLoginResponder implementsIResponder
{
publicfunctionresult(data:Object)
{
// result implementation…
}
publicfunctionfault(info:Object)
{
// fault implementation…
}
}
}
That’s pretty much it. Clean, simple, and yes, more code, however this design supports clean separation of concerns and promotes encapsulation and code reusability.
At the end of the day it really comes down to personal preference. For me, I always prefer to have more classes which encapsulate very specific tasks and responsibilities. As long as you have a clear and concise, but most of all, consistent design you usually can’t go wrong.
就这样了,简单,更多代码,但是这种设计支持了更好的解耦和,以及促进了封装和代码复用,最后看来也许真是个人的偏好起了影响,我哥人喜欢更多的类来封装特定的任务和职责,只要你想要一个清晰的设计,但是设计的一致性不能出错
Cairngen 2.1November 19th, 2007
Last week Cairngen 2.0was released, and judging by my Firestatstotals there has been on average, roughly 250 downloads per day.
Based on the feedback I have received so far, the single most requested feature users are asking for is an additional target which will generate multiple Event, Command and Business Delegate classes (Sequences) simultaneously.
Ironically, prior to the Cairngen 2.0 release one of the contributors (I don’t remember who, so if you read this please leave a comment and take credit where it is due) added a few additional tasks which did just this.
So after a bit of fine tuning and testing I have added three new targets which are as follows:
create-multiple-sequences-include-delegates
Generates multiple Event, Command and Business Delegate classes simultaneously. To do so simply assign a comma delimited list of Sequence names to the sequence.name property in project.properties.
(e.g. sequence.name=Login, Logout, RegisterUser, UnregisterUser)
create-multiple-sequences-exclude-delegates
Generates multiple Event and Command classes simultaneously. To do so simply assign a comma delimited list of Sequence names to the sequence.name property in project.properties.
(e.g. sequence.name=Login, Logout, RegisterUser, UnregisterUser)
create-multiple-value-objects
Generates multiple Value Object classes simultaneously. To do so simply assign a comma delimited list of VO names to the vo.name property in project.properties.
(e.g. vo.name=Login, Logout, RegisterUser, UnregisterUser)
I have also updated the comments in both the project.propertiesfile and the build.xmlfiles, respectively.
If you have any additional feature requests you would like to see added to Cairngen, or if you have already implemented these features. feel free to leave a comment or send me an email.
Subscribe RSS 1.0 : Subscribe RSS 2.0 :
【累死我了---------------------------------】
本文转自
http://www.ericfeminella.com/blog/