2009年10月29日星期四

IOC 的手工实现与Guice 实现

IOC 的手工实现与Guice 实现

1. 服务类与实现类
public interface Service {
void go();
}

public class ServiceImpl implements Service {
public void go() {
logger.info("ServiceImpl.class");
}
}

public class MockService implements Service {
public void go() {
logger.info("MockService.class");
}
}

2. 客户类,调用服务类,最原始的实现
public class Client {
public void test(boolean args){
Service service = null;
if(args){
service = new ServiceImpl();
service.go();
}else{
service = new MockService();
service.go();
}
}
}

3. 测试类,但使用了工厂模式
public class ServiceFactory {
private ServiceFactory() {}
private static Service instance = new ServiceImpl();

public static Service getInstance() {
return instance;
}

public static void setInstance(Service service) {
instance = service;
}

}

4. 使用了工厂模式后,测试类的实现
public class Client {

public void test(){
Service service = ServiceFactory.getInstance();
service.go();

//跟上面有什么不同?
}
}

5. 对客户类进行测试的类
public void testClient() {
Service previous = ServiceFactory.getInstance();
try {
Client client = new Client();
client.test();
//what be printed?

final MockService mock = new MockService();
ServiceFactory.setInstance(mock);
client = new Client();
client.test();
//what be printed?
}
finally {
//must exists?
ServiceFactory.setInstance(previous);
}
}

6. 手工方式注入客户类,以及对客户类的测试
public class Client {
private final Service service;

public Client(Service service) {
this.service = service;
}

public void test() {
service.go();
}
}

public void testClient() {
MockService mock = new MockService();
Client client = new Client(mock);
client.test();
}

7. Guice 的实现方式
首先实现 Module,将服务类与要注入的测试类绑定
public class MyModule implements Module {
public void configure(Binder binder) {
binder.bind(Service.class)
.to(ServiceImpl.class)
.in(Scopes.SINGLETON);
}
}

//客户类中需要表明哪里需要注入
public class Client {
private final Service service;

@Inject
public Client(Service service) {
this.service = service;
}

public void test() {
service.go();
}
}

8. 测试类
public void testClient() {
Injector injector = Guice.createInjector(new MyModule());
Client client= injector.getInstance(Client.class);
client.test();
}

2009年10月28日星期三

Guice 使用

本文有两个例子,一个是对接口类的实现类的使用者注入,另一个是对接口实现类直接注入.

1. 创建接口与实现
public interface MyService {
void sayHello();
}

public class MyServiceImpl implements MyService {
@Override
public void sayHello() {
System.out.println("hello,Guice.");
}
}

2. 测试实现类
定义测试类,表明这个类是需要注入的
import com.google.inject.Inject;
public class MyServiceTest {
@Inject
MyService service;

public void sayHello(){
System.out.println("MyServiceTest...");
service.sayHello();
}
}

3. 定义注射规则
实现 Module,表明运行时将哪个实现类赋给接口
import com.google.inject.Binder;
import com.google.inject.Module;
public class MyServiceModule implements Module {
@Override
public void configure(Binder binder) {
binder.bind(MyService.class).to(MyServiceImpl.class).in(Scopes.SINGLETON);
}
}

4. 测试
Guice 根据 Module 创建注射者
从注射者获取接口类实例
调用接口方法

import junit.framework.TestCase;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class TestMyService extends TestCase{
public void testS(){
Injector inj = Guice.createInjector(new MyServiceModule());
MyServiceTest m = inj.getInstance(MyServiceTest.class);
m.sayHello();
/**
* 也可以换成以下代码
* Injector inj = Guice.createInjector(new MyServiceModule());
* MyServiceTest m = new MyServiceTest();

* inj.injectMembers(m);
* m.sayHello();
*/

}
}

-------------------------------------------
下面这个例子跟上面相似,只是没有定义测试类(接口实现类使用者,直接对接口实现类进行注入)

1. 创建接口与实现
同上

2. 测试实现类
定义测试类,表明这个类是需要注入的
此步省略,没有定义测试类,后面直接注射实现类

3. 定义注射规则
实现 Module,表明运行时将哪个实现类赋给接口
同上

4. 测试
Guice 根据 Module 创建注射者
从注射者获取接口类实例
调用接口方法
import junit.framework.TestCase;
import com.google.inject.Guice;
import com.google.inject.Injector;

public class TestMyService extends TestCase{
public void testS(){
Injector inj = Guice.createInjector(new MyServiceModule());
//此类与上面的例子不同之处,只是传入的参数不同,此处传入的是实现类
MyServiceTest m = inj.getInstance(MyServiceImpl.class);
m.sayHello();
}
}