JaveでOption型を書くとしたら

[なんちゃってOptionモナド](http://qiita.com/poad1010/items/2435e3bc838e838f9a79)という記事をみて、自分ならこう書くかなぁと思ったのでメモ。

# Option関係のクラス

```java:OnMatchListener.java
package com.example.option;

public abstract class OnMatchListener<T> {
	abstract public void Some(T value);
	abstract public void None();
}
```

```java:Option.java
package com.example.option;

abstract public class Option<T> {
	public T get(){
        throw new UnsupportedOperationException();
	}
	
	abstract protected void action(OnMatchListener<T> listener);
	
	public void match(OnMatchListener<T> listener){
		this.action(listener);
	}
}
```

```java:None.java
package com.example.option;

public final class None<T> extends Option<T> {
	public None(){
		// do nothing
	}

	@Override
	protected void action(OnMatchListener<T> listener) {
		listener.None();
	}
}
```

```java:Some.java
package com.example.option;

public final class Some<T> extends Option<T> {
	private final T mValue;
	
	public Some(T value){
		this.mValue = value;
	}

	public T get(){
		return mValue;
	}

	@Override
	protected void action(OnMatchListener<T> listener) {
		listener.Some(mValue);
	}

}
```

# 使い方

```java:Configuration.java
import com.example.option.*;

public class Configuration {
    public Option<String> get(String key) {
        final String value = System.getProperty(key);
        if (value == null) {
            return new None<String>();
        } else {
            return new Some<String>(value);
        }
    }
}
```

```java:OptionTest.java
import com.example.option.*;

public class OptionTest {

	public static void main(String args[]){
		final Configuration config = new Configuration();
		final Option<String> opt = config.get("url");

		opt.match(new OnMatchListener<String>(){
			@Override
			public void Some(String value){
			    // 値がある場合の処理
				System.out.println(opt.get());
			}
			@Override
			public void None(){
			    // 値が無い場合の処理
				System.out.println("none");
			}
		});
	}
}
```

# 結論

うん。おおげさだね

# Option関係を１つのクラスにまとめてみる

Option.java, None.java, Some.java, OnMatchListener.javaを１つのクラスにまとめたほうが使い勝手が良さそうな気がしたのでまとめてみた。

```java:Option.java
package com.example.option;

abstract public class Option<T> {
	public T get(){
        throw new UnsupportedOperationException();
	}
	
	protected abstract void action(OnMatchListener<T> listener);
	
	public void match(OnMatchListener<T> listener){
		this.action(listener);
	}

	/*
	 * class OnMatchListener
	 */
	public abstract static class OnMatchListener<T> {
		abstract public void Some(T value);
		abstract public void None();
	}

	/*
	 * class None
	 */
	public static final class None<T> extends Option<T> {
		public None(){
			// do nothing
		}

		@Override
		protected void action(OnMatchListener<T> listener) {
			listener.None();
		}
	}

	/*
	 * class Some
	 */
	public static final class Some<T> extends Option<T> {
		private final T mValue;
		
		public Some(T value){
			this.mValue = value;
		}

		public T get(){
			return mValue;
		}

		@Override
		protected void action(OnMatchListener<T> listener) {
			listener.Some(mValue);
		}

	}
}
```

テスト用のクラスはimportだけ書き換えればオッケーかな。

```java:Configuration.java
import com.example.option.Option;
import com.example.option.Option.None;
import com.example.option.Option.Some;
```

```java:OptionTest.java
import com.example.option.Option;
import com.example.option.Option.OnMatchListener;
```