CoCと保守性


もしかしたら両立しないかも。

コードがIDEで簡単に終えるってのはメリットだし、規約では暗黙知になってしまいがち。

と、Crazybobさんに言われてしまいましたw

たしかに、可視性・追跡可能性は、コードに明示的に書いてあるほうが高い。

protected void configure() {
  bind(Service.class).to(ServiceImpl.class).to(Scopes.SINGLETON);
}


一目瞭然。

ただしデメリットとして、大量にある場合には何かの対処が必要になりそう。

ひたすら書くのかなあ。それはちょっと避けたい。

一方、規約は俯瞰したときの一貫性というか見易さは圧倒的に高いと思う。

しかし個別で調査しだしたときに、規約の詳細をどこまで知っているかがポイントに

なりがちになると規約ベースが不利になってしまう。


また、例えばドキュメントにきちんと記載したときの覚えやすさは

規約のほうがあると思うけど(全部詳細にドキュメントに書きすぎて探せないみたいなの

よくあるし^^;)、そもそも直感的で覚えやすい規約はドキュメントに書かなくても

ある程度わかるべきかも。


規約は最小限のわかりやすい構成にしておいて、そこから先に何を適用するのか、何が良い選択肢か、

これが最近の考えていることです。

CoCベース、でもCoCドリブンじゃないところが良いポジションなのかも。

Guice with Seasar2


まあ、まんまだけど。

本体。

public class Seasar2Integration {

	static {
		SourceProviders.skip(Seasar2Integration.class);
	}

	private Seasar2Integration() {
	}

	public static <T> void bindComponent(Binder binder, S2Container container,
			String name, Class<T> type) {
		Seasar2Provider<T> provider = new Seasar2Provider<T>(type, name);
		provider.setContainer(container);
		binder.bind(type).annotatedWith(Names.named(name)).toProvider(provider);
	}

	public static <T> void bindAllComponents(Binder binder,
			S2Container container) {
		for (int i = 0; i < container.getComponentDefSize(); i++) {
			final ComponentDef componentDef = container.getComponentDef(i);
			final String componentName = componentDef.getComponentName();
			final Class<?> componentClass = componentDef.getComponentClass();
			bindComponent(binder, container, componentName, componentClass);
		}
	}

	public static <T> Provider<T> fromSeasar2(Class<T> type, String name) {
		return new InjectableSeasar2Provider<T>(type, name);
	}

	static class Seasar2Provider<T> implements Provider<T> {

		private S2Container container;

		private final Class<T> type;

		private final String name;

		public Seasar2Provider(Class<T> type, String name) {
			this.type = type;
			this.name = name;
		}

		void setContainer(S2Container container) {
			this.container = container;
		}

		public T get() {
			return type.cast(container.getComponent(name));
		}

	}

	public static class InjectableSeasar2Provider<T> extends Seasar2Provider<T> {

		public InjectableSeasar2Provider(Class<T> type, String name) {
			super(type, name);
		}

		@Inject
		@Override
		public void setContainer(S2Container container) {
			super.setContainer(container);
		}
	}
}


Test。

public class Seasar2IntegrationTest extends TestCase {

	public void testS2ContainerOnly() throws Exception {
		S2Container container = new S2ContainerImpl();
		container.register(HogeImpl.class);
		container.register(FooImpl.class);

		Foo foo = (Foo) container.getComponent(Foo.class);
		assertEquals("hoge", foo.getName());
		System.out.println(foo.getName());
	}

	public void testBindComponentS2ContainerWithGuice() throws Exception {
		final S2Container container = new S2ContainerImpl();
		container.register(HogeImpl.class, "hoge");
		container.register(FooImpl.class, "foo");

		Injector injector = Guice.createInjector(new AbstractModule() {

			@Override
			protected void configure() {
				bind(S2Container.class).toInstance(container);
				bind(Hoge.class).toProvider(
						Seasar2Integration.fromSeasar2(Hoge.class, "hoge"));
				bind(Foo.class).toProvider(
						Seasar2Integration.fromSeasar2(Foo.class, "foo"));
			}

		});

		Hoge hoge = injector.getInstance(Hoge.class);
		assertNotNull(hoge);
		assertSame(hoge, injector.getInstance(Hoge.class));

		Foo foo = injector.getInstance(Foo.class);
		assertEquals("hoge", foo.getName());
	}

	public void testBindAllComponentS2ContainerWithGuice() throws Exception {
		final S2Container container = new S2ContainerImpl();
		container.register(HogeImpl.class, "hoge");
		container.register(FooImpl.class, "foo");

		Injector injector = Guice.createInjector(new AbstractModule() {

			@Override
			protected void configure() {
				Seasar2Integration.bindAllComponents(binder(), container);
			}

		});

		Key<HogeImpl> hogeKey = Key.get(HogeImpl.class, Names.named("hoge"));
		Key<FooImpl> fooKey = Key.get(FooImpl.class, Names.named("foo"));

		assertNotNull(injector.getInstance(hogeKey));
		assertSame(injector.getInstance(hogeKey), injector.getInstance(hogeKey));

		assertNotNull(injector.getInstance(fooKey));
		assertSame(injector.getInstance(fooKey), injector.getInstance(fooKey));

		Foo foo = injector.getInstance(fooKey);
		assertEquals("hoge", foo.getName());
	}

	public static interface Hoge {

		String getName();
	}

	public static class HogeImpl implements Hoge {

		public String getName() {
			return "hoge";
		}

	}

	public static interface Foo {

		String getName();
	}

	public static class FooImpl implements Foo {

		private Hoge hoge;

		public Hoge getHoge() {
			return hoge;
		}

		public void setHoge(Hoge hoge) {
			this.hoge = hoge;
		}

		public String getName() {
			return hoge.getName();
		}

	}
}


ちょー適当です。ちなみに新たに追加したjarは、
・s2-framework-2.4.11.jar
javassist-3.4.ga.jar

だけ。もしかしたら足りてないw


bindAllはテストしてない。

(追記)

あ、bindAllがこけるw


修正した。Key.getの使い方が間違ってたみたい。