锁定老帖子 主题:贫血就贫血,咂地?
精华帖 (1) :: 良好帖 (0) :: 新手帖 (1) :: 隐藏帖 (0)
|
|
---|---|
作者 | 正文 |
发表时间:2005-11-16
ajoo 写道 1。使用aspectj得到的所谓单点维护的效果用service locator完全可以得到。两相比较,service locator的坏处aspectj的方法同样有。而service locator还比aspectj直观,简单。 所以,aspectj被排除法简单地排除了。呵呵。 不同意,orm刚出道时,其load数据也没有bmp直观。现在大家一样接受了。 ajoo 写道 3。无论如何。对hyperaemia model的依赖注入是比较尴尬的。反过来想,这是不是可以算是充血模型的一个问题点呢?反正贫血模型就没这个毛病。 没有办法,rich model依赖两层关系,第一是数据依赖,一个是对象依赖。 用数据库关系来表述就是:一个rich model即依赖于行(数据依赖),也依赖于表(对象依赖)。 如果把依赖于表的关系,都放入行中,问题消失,不过我想在javaeye里没有人会这么做。 但是在某些特殊的情况下,会出现此种情况,即在某列中存储一个类的full name,用hibernate的customer type来完成加载。 |
|
返回顶楼 | |
发表时间:2005-11-16
ajoo 写道 两个星期没时间上论坛。这个帖子就沉下去了?
顶起来! 总结一下我的观点: 1。使用aspectj得到的所谓单点维护的效果用service locator完全可以得到。两相比较,service locator的坏处aspectj的方法同样有。而service locator还比aspectj直观,简单。 所以,aspectj被排除法简单地排除了。呵呵。 2。service locator和dependency injection的区别我就不多说了。DI要求你声明一个依赖,并且从外面注入一个domain工厂,不可以直接new domain object。 service locator要求你在domain object里面必须调用locator.get(),灵活性有所缺陷,单元测试能力减弱。 如何抉择,就是是否采用ioc同样的理由了。不赘述。 3。无论如何。对hyperaemia model的依赖注入是比较尴尬的。反过来想,这是不是可以算是充血模型的一个问题点呢?反正贫血模型就没这个毛病。 2。service locator和dependency injection的区别我就不多说了。DI要求你声明一个依赖,并且从外面注入一个domain工厂,不可以直接new domain object。 service locator要求你在domain object里面必须调用locator.get(),灵活性有所缺陷,单元测试能力减弱。 如何抉择,就是是否采用ioc同样的理由了。不赘述。 说灵活性有所缺陷,单元测试能力减弱。 未免有点武断了吧。 灵活性丝毫没有影响。IOC虽然是一个很好的模式,但是也不要把它当作一个必然要采用的模式。 比如这么一个Account类,很多人自然而然的就是这样写IOC的: public class Account { private AccountService service; //getter setter public void yourBizLogic();{ //do your logic here //call the service method this.service.doSomeLogic();; } } 那么如果不用IOC模式而采用ServiceLocator模式呢,可以写成这样: public class ServiceLocator{ public static ServiceLocator instance();{ } public Object getService(String serviceID);{ return context.getBean(serviceID);; } } public class Account{ public static final String ACCOUNT_SERVICE_ID="accountService"; public AccountService getAccountService ();( return ServiceLocator.instance();.getService(ACCOUNT_SERVICE_ID);; } public void yourBizLogic();{ //do your logic here //call the service method this.getAccountService ();.doSomeLogic();; } } 模拟单元测试的步骤几乎和原来的一样,你需要做得仅仅是将MockService放到ServiceLocator中,使得ServiceLocator返回你的Mock对象即可。 至于灵活性,我想ServiceLocator没有什么不灵活的,如果要换取一个IOC /TransactionMananger Container,我想在ServiceLocator就可以很好的完成了。 用ServiceLocator隔离Domain Model对IOC容器和具体Service的依赖,我不觉的灵活性有什么降低。 IOC/AOP一样可以在ServiceLocator作,只不过不是不是直接在Domain model 上起作用而已。 IOC,好但不是我们生活的全部。 |
|
返回顶楼 | |
发表时间:2005-11-16
firebody 写道 IOC/AOP一样可以在ServiceLocator作,只不过不是不是直接在Domain model 上起作用而已。
IOC,好但不是我们生活的全部。 AOP还可以这样: public interface IServiceBinder { void bind(Object obj);; } public abstract aspect ServiceInjector { protected pointcut newDomainObject();: call(DomainObject+.new(..););; } public aspect RealServiceInjector extends ServiceInjector { private IServiceBinder serviceBinder; public void setServiceBinder(IServiceBinder serviceBinder); { this.serviceBinder = serviceBinder; } after(); returning(DomainObject domainObject);: newDomainObject(); { serviceBinder.bind(domainObject);; } } public aspect MockServiceInjector extends ServiceInjector { after(); returning(DomainObject domainObject);: newDomainObject(); { Account account = (Account);domainObject; account.setService(new MockXXXService(););; } } 测试方法有两种: 通过DI, aspect ServiceInjector可以避免同ServiceLocator的耦合。 另外,自己可以写一个mock aspect仅仅注入需要测试的服务。 |
|
返回顶楼 | |
发表时间:2005-11-16
引用 你需要做得仅仅是将MockService放到ServiceLocator中,使得ServiceLocator返回你的Mock对象即可
所需要做的仅仅是改代码? 这就是所谓的“单元测试”?要是n个test case要模拟的对象不同怎么办?弄个ant script自动改源代码,自动编译? 还是写n个ServiceLocator类,放在不同的地方,用不同的classloader来载入? |
|
返回顶楼 | |
发表时间:2005-11-16
ajoo 写道 引用 你需要做得仅仅是将MockService放到ServiceLocator中,使得ServiceLocator返回你的Mock对象即可
所需要做的仅仅是改代码? 这就是所谓的“单元测试”?要是n个test case要模拟的对象不同怎么办?弄个ant script自动改源代码,自动编译? 还是写n个ServiceLocator类,放在不同的地方,用不同的classloader来载入? 不理解你的意思。简单得事情也不要搞得复杂吧。 代码: public class ServiceLocator { private static ApplicationContext context; public static void setApplicationContext(ApplicationContext context_);{ context=context_; } private static ApplicationContext getContext(); { if (context == null); { context = new ClassPathXmlApplicationContext( "ctais/config/applicationContext-JDO.xml");; } return context; } public ServiceLocator(); { super();; } public static Object getService(String serviceName); { return getContext();.getBean(serviceName);; } } public class MockApplicationContext implements ApplicationContext { private Map context=new HashMap();; public void addYourMockService(String beanName,Object mockService);{ this.context.put(beanName,mockService);; } public MockApplicationContext(); { super();; } .. } |
|
返回顶楼 | |
发表时间:2005-11-17
却原来你的ApplicationContext也是变种地通过DI进去的。
这样倒是也有了一定的DI的灵活性的优点。 缺点也不少: 1。没有synchronized。线程安全是个隐患。用了synchronized,效率又有影响。 2。这个全局的application context变量对维护是个隐患。如果测试代码里需要频繁更换各种不同的mock,这个状态变换容易引起bug。 2。注射逻辑只能全局范围内统一变化。无法针对某个请求者进行特定处理。比如,DI的话,在业务代码里我可以: new A(b1);.run();; new A(b2);.run(););; 而你的service locator的话: class A{ void run();{ B b = ServiceLocator.getB();; .... } } 你就无法在程序内部依据程序逻辑来选择合适的策略。僵化死板。 |
|
返回顶楼 | |
发表时间:2005-11-17
ajoo 写道 却原来你的ApplicationContext也是变种地通过DI进去的。
这样倒是也有了一定的DI的灵活性的优点。 缺点也不少: 1。没有synchronized。线程安全是个隐患。用了synchronized,效率又有影响。 2。这个全局的application context变量对维护是个隐患。如果测试代码里需要频繁更换各种不同的mock,这个状态变换容易引起bug。 2。注射逻辑只能全局范围内统一变化。无法针对某个请求者进行特定处理。比如,DI的话,在业务代码里我可以: new A(b1);.run();; new A(b2);.run(););; 而你的service locator的话: class A{ void run();{ B b = ServiceLocator.getB();; .... } } 你就无法在程序内部依据程序逻辑来选择合适的策略。僵化死板。 赫赫,如果这样的话,那么代码永远写不出来了,只有写出来的可运行的代码,我们使用了它才知道它有何需要改进的。 只要你想让它变得更好,事情总归会变得更好的。 至于你举的例子,我想A(b) 产生的逻辑就不是一个简单的生成对象的逻辑,我想你这个例子是跟业务相关的,我会把A的构造起Private,然后通过一个具体与业务相关的静态工厂方法来获得已经组合得到真正服务的A实例对象。 |
|
返回顶楼 | |
发表时间:2005-11-17
没什么写不出来的。用DI,代码简单直观。这些复杂问题都不用考虑了。
灵活性一点也不会丢失。 |
|
返回顶楼 | |
发表时间:2005-11-17
这个话题再战下去好象也没有多大的意义,几种方案基本上都是半斤八两,没有决定性的取胜因素,ajoo略占上风。还是换个话题再战吧。
|
|
返回顶楼 | |