该帖已经被评为良好帖
|
|
---|---|
作者 | 正文 |
发表时间:2008-03-13
robbin 写道 ajoo 写道 robbin 写道 我不这么看。这个ViewBlog类似Webwork的Action,本身是prototype的,每次请求创建,为啥就不能有状态呢?就是RoR的controller也是一样,每次请求创建controller实例。 再说@Event,这个就是Webwork里面的Interceptor的东西,起到AOP作用的,在RoR里面也有类似的Filter概念,没觉得加一个@Event怎么会复杂。 不过话说回来,在ViewBlog这个具体的例子当中,使用@Event的方式来初始化数据,的确没有必要,例子举的不恰当。 状态不可怕,可怕的是状态变迁。这个例子里面,就涉及了before initialized和initialized两个状态。而且优先使用immutable也是基本的best practice吧?Guice也是强调constructor injection的。 interceptor不会有状态变化,所以无所谓。要说这个,更象servlet的init(),老掉牙很丑陋的东西。 你说的固然有道理,但更像是一种编程味道的好恶,特别是这个例子的确举的不好。但它这样用,也不会导致代码出啥问题吧? 一个框架的评判很多时候是不能不去闻味道的。象这种给pojo强加一个特殊的中间状态并且不允许immutable的,我觉得不是很轻量,而且也和Guice的一贯精神不符。 |
|
返回顶楼 | |
发表时间:2008-03-13
看来ajoo大哥很喜欢immutable,所以尤其喜欢Constructor injection
引用 Guice best practices
Field vs. method vs. constructor injection Field injection * + Most compact syntax (good for a trivial custom provider, e.g.) * - Can't take any special action upon injection * - Your class is not testable! Method injection * + Isn't field injection * + Only thing that works for some strange edge cases Constructor injection * + Fields can be final! * + Injection cannot possibly have been skipped, even if Guice is not in the picture * + Easy to see dependencies at a glance * + It's what the idea of construction is all about * - No optional injections * - Useless when Guice can't do instantiation itself, e.g. a servlet * - Subclasses need to "know about" the injections needed by their superclasses * - Less convenient for tests that only "care about" one of the parameters 不过上面有些概念还是没有很多经验来体会差别,劳烦ajoo大哥您给讲讲?比如 * - Your class is not testable! * + Only thing that works for some strange edge cases * - Useless when Guice can't do instantiation itself, e.g. a servlet 你举的那个代码,每个请求都要对应一个action的构造函数,那怎么用url/actionmethod mapping?根据struts2.1的rest plugin,我臆想了一段伪码如下: public final class BlogsController { private final Blogs blogs; @Inject public BlogsController(Blogs blogs){ this.blogs = blogs; } /** GET /blogs/?page={page} */ @Resource("/blogs/") @RestMethod("GET") @RestAccept("text/html") public Renderer index(@RestParam("page") int page) { return new Renderer("index.html") .put("blogs", blogs.list(page)); } /** GET /blogs/1 */ @Resource("/blogs/{id}") @RestMethod("GET") @RestAccept("text/json") public Renderer show(@RestParam("id") String id) { Blog blog = blogs.get(id); return new Renderer("show.json") .withEtag(...) .lastModified(blog.getLastModified()) .put("blog", blog); } /** PUT /blogs/1 */ @Resource("/blogs/{id}") @RestMethod("PUT") @RestAccept("text/html") public Renderer update(???) { // how to do when we need to store some values from request into pojo but can't change pojo's //state for protecting ajoo's faith? varargs in method scope? //prepare , parameter/property binder, then save return index(0); } ... } public class Renderer { private Map context; public Render(String result); @Inject public void setResponse(HttpResponse res); @Inject public void setResponse(HttpRequest req); public put(String key, Object value); public void render(); ... } action pojo想要immutable,就得需要写mutable的Renderer和Binder之类的设施来存放中间状态。只不过是换了个地方而已。 |
|
返回顶楼 | |
发表时间:2008-03-13
* - Your class is not testable!
field基本上都是private的。你没法在test case里面给它设一个mock值。Guice不象Spring,它老老实实告诉你,写单元测试不要靠容器,而是用JUnit/TestNG。 * + Only thing that works for some strange edge cases 不清楚。可能是说lifecycle的情况或者你需要做除了赋值以外的其它特殊动作。 * - Useless when Guice can't do instantiation itself, e.g. a servlet servlet是由servlet容器直接调用无参构造函数创建的,Guice插不进去。 至于说这个rest的例子。我觉得warp和我的理想用法的共同点都是:直接的domain模型,一个对象代表一个资源。所以对rest method的响应不在这个pojo里面。分歧只在于我希望更直接的构造函数完成一切,而不是一些人为定义的特殊事件。 一个假想的用法是: interface ResourceLocator { <T> T getResource(String path, Class<T> resourceType); } class FooServlet extends HttpServlet { private ResourceLocator locator; public void doGet(HttpServletRequest request, HttpServletResponse response) { Foo foo = locator.getResource(request.getServletPath(), Foo.class); // foo对象就是一个完全注射好的,对象当前请求的资源的实例。 response.getWriter().write(foo.getName()); } } |
|
返回顶楼 | |
发表时间:2008-03-13
我觉得ajoo现在有些跟自己较劲的意思。其实就这个事情来说,本无所谓对错,都有道理。关键是自己的权衡和选择。
而之所以我最近很少发表对java社区的看法,原因当然是我自己对java就不太通,水平不够。但是我还以为,java社区的框架看似不少,但是真正的说起来,又没多少。这些框架之间的哲学思路其实分析起来,仅仅是细节层面的不同,而无本质上的区别。而现在构架师满天飞,又看不出哪个出来设计一个自己的框架来。要说grails哲学稍微有所不同,但是又是外来户,不能算本土球员。 而本身java社区的框架层出不穷,就说明java这里需要框架这样的开发套路。而同时又可以说明,这些套路又都不是令人满意。因此我看,与其发明更多的套路,不如发明组织套路的法子出来,叫大家学会这个法子,自己整自己的套路出来来得彻底。 |
|
返回顶楼 | |
发表时间:2008-03-14
谢谢ajoo。资源定位器这个概念我理解了。不过我对REST的理解很肤浅,可能太局限于现有这些框架的路子。某个框架,或者某个想法出来了,首先用熟悉框架的经验去考察它。
|
|
返回顶楼 | |
发表时间:2008-03-14
ozzzzzz 写道 我觉得ajoo现在有些跟自己较劲的意思。其实就这个事情来说,本无所谓对错,都有道理。关键是自己的权衡和选择。 而之所以我最近很少发表对java社区的看法,原因当然是我自己对java就不太通,水平不够。但是我还以为,java社区的框架看似不少,但是真正的说起来,又没多少。这些框架之间的哲学思路其实分析起来,仅仅是细节层面的不同,而无本质上的区别。而现在构架师满天飞,又看不出哪个出来设计一个自己的框架来。要说grails哲学稍微有所不同,但是又是外来户,不能算本土球员。 而本身java社区的框架层出不穷,就说明java这里需要框架这样的开发套路。而同时又可以说明,这些套路又都不是令人满意。因此我看,与其发明更多的套路,不如发明组织套路的法子出来,叫大家学会这个法子,自己整自己的套路出来来得彻底。 你这样说未免也太大了吧,从宣传上来讲,各个框架都有各自的宣传渠道或者是相当数量的布道者,每年都有相当数量的框架和自己号称是框架的东西出现,暂且认为都是框架吧,这些框架有些是特定条件下的产物,如早期的struts和webwok都是某些人基于在公司中的需要衍生出来的,有些是挂羊头卖狗肉如IBM在幕后操纵的,还有些一开始就为了商业目的启动的。还有些是为了解决特定领域的问题,你说的好像仅仅局限在web框架中啊。我认为即使是在web框架中,根据不同的系统特性,本来就有很多种业务特点和系统特点,有多种适合不同情况的框架的选择权本身就很好,难道一定要像微软那样大家都用一套,听起来不错,能减少重复劳动,实际呢,垄断带来死气沉沉和不思进取,从这个角度上来说新的框架出现对老框架地推动和鞭策也是很有效果的。
组织套路也算是个领域,也有类似框架和方法论的。“java这里需要框架这样的开发套路”不等于“我们需要把所有的框架集成起来”。 |
|
返回顶楼 | |
发表时间:2008-03-14
花这么多时间讨论guice?没有看看tapestry-ioc吗?
吸收了很多guice的东东,而且可以独立的使用在应用程序中,而不是和tapestry web framework 绑定的。 |
|
返回顶楼 | |
发表时间:2008-03-14
robbin 写道 melin 写道 rainlife 写道 使用struts2(CoC)+JPA+spring(注解),会是怎么样呢?
在java中这样的组合应该成经典,如果一味的最求zero 配置,也不是很完美,应该是注解和xml相结合,基本不会变动用注解,如果那些可变动的还是需要xml的,特别是spring2.5。提供的新特性(@Component,@Repository,@Service),大大简化了典型的三层结构的配置。 Spring在静态的配置文件当中描述bean的依赖关系(或者静态的Annotation),在某些情况下这是一个非常讨厌的限制,导致你很难在程序运行期修改或者创建bean的依赖关系。 比方说,你的程序根据某用户的操作,创建了quartz bean执行后台任务,这玩意你没办法事先在配置文件里面写死的,那你就麻烦大了,只能想办法自己写FactoryBean,在程序里面调用这个FactoryBean自己手工创建依赖。再例如你一个prototype的bean,在程序运行期创建的时候需要从程序里面传入一个构造器参数,这个参数可能来自你的业务逻辑,那你马上傻眼了,写FactoryBean吧,在程序里面自己create吧。类似这种情况还挺多的,Spring也就是管理Singleton的bean很好用,一旦涉及到prototype bean啥的,处处受限制。 所以这个IoC的玩意,你要在程序运行期玩花样,灵活起来,动态起来,Google Guice就比Spring好用不是一点半点。这就是为啥我推崇基于Google Guice的warp的原因,当然warp自己也有一些很不错的地方。 1.spring要更改bean的依赖关系可以手动的去get和set,也可以采用spring-dm,这是osgi的强项,不知道guice有什么更好的方法? 2.你说的quartz bean还是在自己的带面里面传入构造参数new出来比较好,然后获取spring里面org.quartz.Scheduler的实例,然后按照quartz的方式去处理,既然这个bean的构造参数是依赖业务逻辑不断的变,难道guice可以检测到然后得到不同的实例? 个人认为采用guice比采用spring好的只是代码上的优雅,对于设计并没有什么新意,因为IoC最近也没什么新概念,guice只是采用jdk5的annotation方式. |
|
返回顶楼 | |
发表时间:2008-03-14
sorphi 写道 看来ajoo大哥很喜欢immutable,所以尤其喜欢Constructor injection
引用 Guice best practices
Field vs. method vs. constructor injection Field injection * + Most compact syntax (good for a trivial custom provider, e.g.) * - Can't take any special action upon injection * - Your class is not testable! Method injection * + Isn't field injection * + Only thing that works for some strange edge cases Constructor injection * + Fields can be final! * + Injection cannot possibly have been skipped, even if Guice is not in the picture * + Easy to see dependencies at a glance * + It's what the idea of construction is all about * - No optional injections * - Useless when Guice can't do instantiation itself, e.g. a servlet * - Subclasses need to "know about" the injections needed by their superclasses * - Less convenient for tests that only "care about" one of the parameters 不过上面有些概念还是没有很多经验来体会差别,劳烦ajoo大哥您给讲讲?比如 * - Your class is not testable! * + Only thing that works for some strange edge cases * - Useless when Guice can't do instantiation itself, e.g. a servlet 你举的那个代码,每个请求都要对应一个action的构造函数,那怎么用url/actionmethod mapping?根据struts2.1的rest plugin,我臆想了一段伪码如下: public final class BlogsController { private final Blogs blogs; @Inject public BlogsController(Blogs blogs){ this.blogs = blogs; } /** GET /blogs/?page={page} */ @Resource("/blogs/") @RestMethod("GET") @RestAccept("text/html") public Renderer index(@RestParam("page") int page) { return new Renderer("index.html") .put("blogs", blogs.list(page)); } /** GET /blogs/1 */ @Resource("/blogs/{id}") @RestMethod("GET") @RestAccept("text/json") public Renderer show(@RestParam("id") String id) { Blog blog = blogs.get(id); return new Renderer("show.json") .withEtag(...) .lastModified(blog.getLastModified()) .put("blog", blog); } /** PUT /blogs/1 */ @Resource("/blogs/{id}") @RestMethod("PUT") @RestAccept("text/html") public Renderer update(???) { // how to do when we need to store some values from request into pojo but can't change pojo's //state for protecting ajoo's faith? varargs in method scope? //prepare , parameter/property binder, then save return index(0); } ... } public class Renderer { private Map context; public Render(String result); @Inject public void setResponse(HttpResponse res); @Inject public void setResponse(HttpRequest req); public put(String key, Object value); public void render(); ... } action pojo想要immutable,就得需要写mutable的Renderer和Binder之类的设施来存放中间状态。只不过是换了个地方而已。 Guice推荐ctor injection,我来点评一下他说的优点 * + Fields can be final! 这个有什么实际意义? * + Injection cannot possibly have been skipped, even if Guice is not in the picture 如果用方法注入,可以加一个比如@Required来强制必须注入 * + Easy to see dependencies at a glance 这个是鸡肋 * + It's what the idea of construction is all about 这个没明白说什么 再来加一个缺点,和getter/setter注入相比没办法在运行期改变,拿acegi举例 CONVERT_URL_TO_LOWERCASE_BEFORE_COMPARISON \A/backend/switchuser\Z=ROLE_SUPERVISOR \A/backend/switch\Z=ROLE_SUPERVISOR \A/backend/exit\Z=ROLE_PREVIOUS_ADMINISTRATOR \A/backend/.*\Z=ROLE_SUPERVISOR 这个是控制url访问权限的配置,在容器启动的时候就注入到bean里面了,也可以在webapp运行期间,修改它然后再set进去 |
|
返回顶楼 | |
发表时间:2008-03-14
ozzzzzz 写道 我觉得ajoo现在有些跟自己较劲的意思。其实就这个事情来说,本无所谓对错,都有道理。关键是自己的权衡和选择。
而之所以我最近很少发表对java社区的看法,原因当然是我自己对java就不太通,水平不够。但是我还以为,java社区的框架看似不少,但是真正的说起来,又没多少。这些框架之间的哲学思路其实分析起来,仅仅是细节层面的不同,而无本质上的区别。而现在构架师满天飞,又看不出哪个出来设计一个自己的框架来。要说grails哲学稍微有所不同,但是又是外来户,不能算本土球员。 而本身java社区的框架层出不穷,就说明java这里需要框架这样的开发套路。而同时又可以说明,这些套路又都不是令人满意。因此我看,与其发明更多的套路,不如发明组织套路的法子出来,叫大家学会这个法子,自己整自己的套路出来来得彻底。 死胖子是说springside这类的东西么? |
|
返回顶楼 | |