23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Java8が好きになる話(StreamAPIの話はしない) その3 インターフェースのデフォルト実装

Last updated at Posted at 2015-07-11

今回もラムダ書きますけど、重要なのはそこではないので勘弁してください。

java8でインターフェースでデフォルト実装が書けるようになりました。
参考:http://www.ne.jp/asahi/hishidama/home/tech/java/interface.html#h_default_method
いつ使うの?abstractクラスの実装と何が違うの?と言われると「うっ」ってなりますが、
個人的な意見では仕様変更(機能追加)に強くなったのかと思ってます。
関数型インターフェースでは多用しますけど今回はその話はしません。)

#例(仕様)
Containerインターフェースはkeyとuserから情報を返します。
実装クラスに下記の2種類1があります。

  • 生成時に情報をロードしてキャッシュします。要求にはキャッシュから情報を返します。
  • 要求に対して情報をロードして返します。一度ロードした情報はキャッシュします。

#コード

	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);
	}

	public static class CacheContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		public CacheContainer() {
			//TODO 初期処理でmapに情報を積む
		}

		@Override
		public String get(String key, String user) {
			return this.map.getOrDefault(key, Collections.emptyMap()).get(user);
		}
	}

	public static class DemandContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		@Override
		public String get(String key, String user) {
			return this.map.computeIfAbsent(key, k -> new HashMap<>())
					.computeIfAbsent(user, k -> this.getFromDB(key, user));
		}

		/**
		 * たとえばDBから値をとってきて返す。
		 */
		private String getFromDB(String key, String user) {
			return null;//TODO DBからとってくる処理
		}
	}

#機能拡張(default実装なし2
これに機能拡張が必要になって、
Containerに

String get(String key);

というメソッドを増やして、get(key,"DEFAULT");と同じ動きをさせたい。
みたいな要件来たらどうします?

default実装なし
	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);

		/**
		 * keyから情報を返す<br>
		 * get(key,"DEFAULT");と同様
		 */
		String get(String key);
	}

	public static class CacheContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		public CacheContainer() {
			//TODO 初期処理でmapに情報を積む
		}

		@Override
		public String get(String key, String user) {
			return this.map.getOrDefault(key, Collections.emptyMap()).get(user);
		}

		//New!!
		@Override
		public String get(String key) {
			return this.get(key, "DEFAULT");
		}
	}

	public static class DemandContainer implements Container {
		private final Map<String, Map<String, String>> map = new HashMap<>();

		@Override
		public String get(String key, String user) {
			return this.map.computeIfAbsent(key, k -> new HashMap<>())
					.computeIfAbsent(user, k -> this.getFromDB(key, user));
		}

		//New!!
		@Override
		public String get(String key) {
			return this.get(key, "DEFAULT");
		}

		/**
		 * たとえばDBから値をとってきて返す。
		 */
		private String getFromDB(String key, String user) {
			return null;//TODO DBからとってくる処理
		}
	}

あーあ。2か所に同じこと書くなんて。
abstractクラスかませておけばよかったと後悔するしかないですね。
実装クラスが2つしか無かったことが不幸中の幸いです。

#機能拡張(java8 default実装)
java8のdefault実装ならば!!!

java8
	/**
	 * インターフェース
	 */
	public interface Container {
		/**
		 * keyとuserから情報を返す
		 */
		String get(String key, String user);

		/**
		 * keyから情報を返す<br>
		 * get(key,"DEFAULT");と同様
		 */
		default String get(String key) {
			return this.get(key, "DEFAULT");
		}
	}

とdefaultメソッド増やすだけでOK!

#おまけ
こういう感じでメソッドを増やすことができるdefaultメソッドのおかげで
java8のCollectionやMapたちも大成長を遂げたといっても過言ではありませんね。
参考:http://www.lambdafaq.org/what-are-default-methods/
(英語。僕はGoogle翻訳で読みました)
そういう意味でもデフォルト実装は大好きです。

#おまけ2
Iteratorを実装することってあります?
僕はほんとたまにあるんですけど3、removeをサポートしないことがほとんどで、

    public void remove() {
        throw new UnsupportedOperationException("remove");
    }

って毎度書くのだるいなー。っと思ってたら、
これデフォルト実装されているので書く必要なくなりましたよ!!

その4につづく。

その1:Java8が好きになる話(StreamAPIの話はしない) その1 Map#computeIfAbsentとList#sort
その2:Java8が好きになる話(StreamAPIの話はしない) その2 Optional#map

  1. 本番機用とデバッグ用でこんな感じに分けたりしません?

  2. 「java7以前」って書きたかったんですけど「default実装なし」と書いたのは、すでにラムダやら使っちゃってるからです。

  3. 年月の無限イテレータとか作りました。昔。

23
25
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
23
25

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?