13章
before, after, and around advice 三种通知的类型, 和Spring本身的AOP概念一样 ps:AspectJ
如果要监听一个对象,进行AOP.那么需要实现GroovyInterceptable接口,接口中的关键方法为invokeMethod 传入的两个参数
然后判断传入的第一个参数String类型,分别调用不同的方法,注意带不同的参数
Car.metaClass.getMetaMethod('check').invoke(this, null)
Groovy下的方法调用,可以不加()符号
不继承接口,操作metaClass的方式,添加拦截的方法
Car.metaClass.invokeMethod = { String name, args ->...}
中间的方法 等同上面接口中的实现,通过metaClass配合{}闭包的方式来使用
对象MetaClass的调用,会随着方法声明的不同,自动的进行变化
使用MOP给对象注入新的行为的方法 有五种
Categories
ExpandoMetaClass
GroovyInterceptable
GroovyObject’s invokeMethod( )
GroovyObject’s methodMissing( )
使用category 方式注入方法
编写一个util类保存公共的方法,方法需要定义成static ,然后返回一个结果
类名StringUtil 方法名字def static toSSN(self)
在目标中调用使用use块
use(StringUtil)
{
println "123456789".toSSN()
println new StringBuffer("987654321").toSSN()
}
这样就可以直接将方法附加在该块里面的方法之上.主要需要在use块内才可以
参数对象可以为Groovy支持的参数,对象和Closure
使用两个参数接受的时候,第一个参数为源对象,另外个可以为{}Closure
可以使用use(Stringutil,findduti) 同时加载多个categories
注意:方法要是static的
方法名同名的时候,最后一个categorie会有最高的优先级
def static toString(String self)
{
def method = self.metaClass.methods.find { it.name == 'toString' }
'!!' + method.invoke(self, null) + '!!'
}
调用源对象的方法
Injecting Methods Using ExpandoMetaClass 使用ExpandoMetaClass 注入方法
使用ExpandoMetaClass 可以添加方法,属性,构造函数,静态方法,和借用其他类的方法,可以用于注入到
POGOs和POJOs
demo :
Integer.metaClass.daysFromNow = { ->
Calendar today = Calendar.instance
today.add(Calendar.DAY_OF_MONTH, delegate)
today.time
}
添加daysFromNow方法到Integer对象上
调用直接用5.daysFromNow() ps:方法后的()可以去掉
另外种赋值的方法添加,方便共用
daysFromNow = { ->
Calendar today = Calendar.instance
today.add(Calendar.DAY_OF_MONTH, (int)delegate
today.time
}
Integer.metaClass.daysFromNow = daysFromNow
....daysFromNow=daysFromNow
对父类添加方法,也会影响到子类中
Number.metaClass.someMethod = { ->
println "someMethod called"
}
2.someMethod()
2L.someMethod()
同理可以将方法添加到一个接口中,那样也将影响到所有的子类
添加静态static方法给指定对象 使用static关键字
Integer.metaClass.static.isEven = { val -> val % 2 == 0 }
添加构造函数给指定对象.使用关键符号 <<
Integer.metaClass.constructor << { Calendar calendar ->
new Integer(calendar.get(Calendar.DAY_OF_YEAR))
}
println new Integer(Calendar.instance)
如果需要替换构造函数 使用=符号代替<< (严格的说,并不能被覆盖其他的构造函数)
Injecting Methods into Specific Instances 在特别的实例注入方法
通过ExpandoMetaClass()的实例来进行创建
Person{}
def emc = new ExpandoMetaClass(Person) //创建实例
emc.sing = { -> //定义方法
'oh baby baby...'
}
emc.initialize() //初始化对象
jack.metaClass = emc //注入方法给指定对象
println jack.sing()
不过该方法只能用在POGOs对象上---即Groovy对象,POJOs的metaClass对象是只读的
Method Synthesis Using methodMissing 使用methodMissing组合方法
在POGOs对象中,直接定义methodMissing方法 接受两个参数
def methodMissing(String name, args){} 然后进行判断,分别判断第一个传入的参数
即方法名,然后分别执行不同的操作
然后在所有该对象的实例中,就会自动调用该方法进行处理
def methodMissing(String name, args)
{
System.out.println "methodMissing called for $name"
def methodInList = plays.find { it == name.split('play')[1]}
if (methodInList)
{
def impl = { Object[] vargs -> //使用数组分解参数
return "playing ${name.split('play')[1]}..."
}
Person.metaClass."$name" = impl //future calls will use this
return impl(args)
}
else
{
throw new MissingMethodException(name, Person.class, args)
}
}
static { Person.metaClass } //这里会有所不同,如果删除掉
}
继承GroovyInterceptable接口实现的,可以和methodMissing 一起使用,会同时起作用,不过接口的优先级较高
invokeMethod方法
def method = metaClass.getMetaMethod(name, args)
methodMissing
def methodInList = plays.find { it == name.split('play')[1]}
Method Synthesis Using ExpandoMetaClass 使用ExpandoMetaClass
代码较长, 关键还是使用了类似的方法 Person.metaClass.methodMissing ={}
class Person
{
def work() { "working..." }
}
Person.metaClass.methodMissing = { String name, args ->
def plays = ['Tennis', 'VolleyBall', 'BasketBall']
System.out.println "methodMissing called for $name"
def methodInList = plays.find { it == name.split('play')[1]}
if (methodInList)
{
def impl = { Object[] vargs ->
return "playing ${name.split('play')[1]}..."
}
Person.metaClass."$name" = impl //future calls will use this
return impl(args)
}
else
{
throw new MissingMethodException(name, Person.class, args)
}
}
类似与上面的例子
使用 Person.metaClass.invokeMethod = { }
Person.metaClass.methodMissing = { }
第一个偏向用于拦截 第二个偏向用于进行监听操作
Synthesizing Methods for Specilic Instances 混合方法,用于特别的实例
class Person {}
def emc = new ExpandoMetaClass(Person)
emc.methodMissing = { String name, args ->
"I'm Jack of all trades... I can $name"
}
emc.initialize()
使用的方法可以参考上面的例子
可以在new初始化对象的时候进行对象方法的重写,也可以直接对实例进行方法的重写
car = new Expando(year: 2007, miles: 0, turn: { println 'turning...' })
car.drive = {
miles += 10
println "$miles miles driven"
}
car.drive()
car.turn()
其中new时候的方法重写,并不会麻烦调用方法
循环一个集合里面对象的每个属性,关键还是最后两个输出参数
cars.each { car ->
for(String property : props) { print "${car[property]} " }
println car."$ampyMethod"()
}
方法的调用
if (delegateTo?.metaClass.respondsTo(delegateTo, name, args))
{
Manager.metaClass."${name}" = { Object[] varArgs ->
return delegateTo.invokeMethod(name, *varArgs)
}
return delegateTo.invokeMethod(name, args)
}
class中也有{}块的使用
{ delegateCallsTo Worker, Expert, GregorianCalendar }
回顾MOP的使用
如果能够修改类的话 可以使其实现Groovyinterceptable类,然后使用其中的invokeMethod方法
如果不能修改类的话,可以使用ExpandoMetaClass 或者categories类
测试
使用Groovy测试Java类
测试用Unit Test case 可以继承GroovyTestCase 是基于Junit3.4 不过也可以直接使用基于注解的方式Junit4.5
注意测试方法的必须返回void,即用void定义方法 而不是简单的只有def
junit.swingui.TestRunner’s run( ) 的使用,方便进行测试
测试类型..随便翻译 1:确定测试 2:拒绝测试 3:异常测试
使用Groovy测试Java类,是一种很好的练习Groovy的方式
Junit测试用的setUp等方法 需要熟悉,就是在测试前进行初始化,对应的tearDown( ) 关闭 4.x中有所不同
三种测试的类型 dmeo
1:positive test
void testInitialize()
{
assertEquals 0, car.miles
}
2:negative test:
void testDrive()
{
car.drive(10)
assertEquals 10, car.miles
}
3:exception tests.
try
{
divide(2, 0)
fail "Expected ArithmeticException ..."
}
catch(ArithmeticException ex)
{
assertTrue true // Success
}
其中异常测试 可以使用Groovy包装好的方法
shouldFail(ArithmeticException) { divide(2, 0) } // ()中为指定的异常,可以为空或者省略(), 后面为所要调用的方法
Groovy下创建xml的方式
bldr = new groovy.xml.MarkupBuilder()
bldr.languages {
language(name: 'C++') { author('Stroustrup')}
language(name: 'Java') { author('Gosling')}
language(name: 'Lisp') { author('McCarthy')}
}
创建后的格式为
<languages>
<language name='C++'>
<author>Stroustrup</author>
</language>
...
</languages>
也可以使用StringWrite的构造方式,将一个xml直接写入一个流中
MarkupBuilder(writer)
langs = ['C++' : 'Stroustrup', 'Java' : 'Gosling', 'Lisp' : 'McCarthy']
writer = new StringWriter()
bldr = new groovy.xml.MarkupBuilder(writer)
bldr.languages {
langs.each { key, value ->
language(name: key) {
author (value)
}
}
}
如果是大规模的xml文件, 应该使用StreamingMarkupBuilder,该方法也能定义NameSpace
langs = ['C++' : 'Stroustrup', 'Java' : 'Gosling', 'Lisp' : 'McCarthy']
xmlDocument = new groovy.xml.StreamingMarkupBuilder().bind {
mkp.xmlDeclaration()
mkp.declareNamespace(computer: "Computer")
languages {
comment << "Created using StreamingMarkupBuilder"
langs.each { key, value ->
computer.language(name: key) {
author (value)
}
}
}
}
Creating DSLs in Groovy 在Groovy中创建DSLs
joesPizza.identity {
setSize(Size.LARGE);
}
其中可以省略用对象名.方法名来要用方法
原来是joesPizza.setSize(Size.LARGE);
也可以省略掉()
快速的开发
循环的形式 有三种
for(i in 0..9) { println i }
0.upto(9) { println it }
10.times { println it }
PS:跳过MOCK,以及DSL部分内容
分享到:
相关推荐
Pragmatic.Bookshelf.Programming.Groovy
Pragmatic.Bookshelf.tmux.2.Productive.Mouse-Free.Development.mobi Pragmatic.Bookshelf.tmux.2.Productive.Mouse-Free.Development.mobi
Pragmatic.Bookshelf.Rails.for.PHP.Developers
Pragmatic.Bookshelf.Deploying.Rails.Applications.May.2008
多位业界专家和Clojure贡献者对Clojure以及相关书籍《Programming Clojure》给予了高度评价: - **David Bock**(Code Sherpas公司主管)认为Clojure扩展了开发者思考编码的方式,是一门引人入胜的语言。 - **Chris...
- **标题**: "Pragmatic.Bookshelf.Agile.Web.Development.with.Rails.5" 该书标题清晰地传达了本书的核心主题——使用 Ruby on Rails 5 进行敏捷 Web 开发。它表明这是一本专注于介绍如何利用 Rails 框架来实现...
《Pragmatic Ajax: A Web 2.0 Primer》是一本深入探讨Ajax技术的书籍,由Pragmatic Bookshelf出版社于2006年4月出版。Ajax(Asynchronous JavaScript and XML)是一种在无需刷新整个网页的情况下更新部分网页内容的...
#### 一、《Pragmatic Bookshelf: Best of Ruby Quiz Mar. 2006》概述 - **书籍标题**:本书名为《Pragmatic Bookshelf: Best of Ruby Quiz Mar. 2006》,是一本专注于Ruby编程语言的经典练习册。 - **书籍内容**:...
《Pragmatic Bookshelf Advanced Rails Recipes May 2008》是一本专注于Rails高级开发实践的书籍,由Pragmatic Bookshelf出版社于2008年5月出版。这本书主要面向已经熟悉Ruby on Rails基础的开发者,旨在通过一系列...
《Mastering Dojo》是2008年6月由Pragmatic Bookshelf出版的一本技术书籍,专注于JavaScript库Dojo的深入学习。这本书详细介绍了Dojo工具集,旨在帮助开发者充分利用这个强大的JavaScript框架,提升Web应用开发的...
《Pragmatic Bookshelf Best of Ruby Quiz Mar 2006》是一本专注于Ruby编程语言的书籍,由Pragmatic Bookshelf出版社出版。这本书的独特之处在于它采用了问答的形式,即"Quiz",来帮助读者深入理解和掌握Ruby的核心...
《Pragmatic Beginning Mac Programming》是面向初学者的一本实用型Mac编程指南,旨在帮助读者快速掌握Mac平台上的软件开发技能。这本书详细介绍了Mac OS X操作系统的基础知识,以及使用Objective-C语言进行编程的...
Data is getting bigger and more complex by the day, and so are your choices in handling it. Explore some of the most cutting-edge databases available - from a traditional relational database to newer ...
### 相关知识点 #### 一、Rails for Java Developers 概览 《Rails for Java Developers》是一本专为Java开发者撰写的书籍,旨在帮助他们快速掌握Ruby on Rails框架。本书由Stuart Halloway和Justin Etheredge合著...
### 相关知识点 #### 一、介绍与框架(Introduction and Frameworks) 1. **图形用户界面(GUI)概述:** - GUI是允许用户通过图形符号和视觉指示进行交互的用户界面形式。 - 它通常包括按钮、菜单、对话框等...
This book is designed for those of us who don’t have a degree in computer science.It’s ... Most importantly, the book is intended for people who have little or no previous programming knowledge.
Publisher: Pragmatic Bookshelf Publication Date: 2015-04-25 ISBN-10: 1941222188 ISBN-13: 9781941222188 Programming Google Glass: Build Great Glassware Apps with the Mirror API and GDK Google Glass ...
### Pragmatic Programming Ruby 1.9:关键知识点解析 #### 标题解析:“Pragmatic.Programming.Ruby.1.9” 此标题表明本书主要介绍的是Ruby 1.9编程语言及其在实用主义编程(Pragmatic Programming)中的应用。...