mike-neckのブログ

Java or Groovy or Swift or Golang

リファクタリングの手順 メソッドの抽出 -> メソッドの別クラスへの移動

IntelliJ での基本的なリファクタリングの手順です。


次のような二つのクラスを考えます。

public class WithAccessTokenSecurityContextFactory implements WithSecurityContextFactory<WithAccessToken> {

    @Override
    public SecurityContext createSecurityContext(final WithAccessToken annotation) {
        final SecurityContext context = SecurityContextHolder.createEmptyContext();
        final GivenAccessToken accessToken = new GivenAccessToken(annotation);
        final AccessTokenEntity accessTokenEntity = accessToken.accessTokenEntity(); // ここから
        final Authentication authentication = new Authentication(accessTokenEntity);
        final OAuth2Authentication oauth2 = authentication.oauth2(); // ここまでを一つにまとめたい
        context.setAuthentication(oauth2);
        return context;
    }
}
class GivenAccessToken {
    GivenAccessToken(final WithAccessToken accessToken) {
        // 省略
    }
    AccessTokenEntity accessTokenEntity() {
        // 省略
    }
}

このように7行もあるメソッドは長すぎるし、利用するクラスが実装を知りすぎているので、一つにまとめて見通しを良くしたいところです。

1. メソッドの抽出

最初に WithAccessTokenSecurityContextFactory の内部に private メソッドとして抽出します。

  • コード内で「ここから」〜「ここまで」とした範囲を選択する

f:id:mike_neck:20180215225007p:plain

  • Refactor > Extract > Method を選択する。あるいは + + M を押す

f:id:mike_neck:20180215225049p:plain

  • ダイアログでメソッドの可視性、型、メソッド名、パラメーターを確認してメソッドの抽出を実行

f:id:mike_neck:20180215225235p:plain

抽出が完了したら次のような形になります。

public class WithAccessTokenSecurityContextFactory implements WithSecurityContextFactory<WithAccessToken> {

    @Override
    public SecurityContext createSecurityContext(final WithAccessToken annotation) {
        final SecurityContext context = SecurityContextHolder.createEmptyContext();
        final GivenAccessToken accessToken = new GivenAccessToken(annotation);
        final OAuth2Authentication oauth2 = oauth2(accessToken);
        context.setAuthentication(oauth2);
        return context;
    }

    private OAuth2Authentication oauth2(final GivenAccessToken accessToken) {
        final AccessTokenEntity accessTokenEntity = accessToken.accessTokenEntity();
        final Authentication authentication = new Authentication(accessTokenEntity);
        return authentication.oauth2();
    }
}

2. メソッドの別クラスへの移動

抽出したメソッドおよび抽出されたメソッドは短くなりますが、今のままだと WithAccessTokenSecurityContextFactoryGivenAccessTokenOAuth2Authentication の内部実装を知りすぎています。このような操作は GivenAccessToken が抑えておけばよい内容です。したがって、 oauth2 メソッドを GivenAccessToken に移動します。

  1. oauth2 メソッドにカーソルをあわせる
  2. Refactor > Move を選択する。あるいは F6

f:id:mike_neck:20180215225916p:plain

  • ダイアログで移動先のクラスを選択して移動を実行

f:id:mike_neck:20180215230032p:plain

移動完了後は次のようになっている

public class WithAccessTokenSecurityContextFactory implements WithSecurityContextFactory<WithAccessToken> {

    @Override
    public SecurityContext createSecurityContext(final WithAccessToken annotation) {
        final SecurityContext context = SecurityContextHolder.createEmptyContext();
        final GivenAccessToken accessToken = new GivenAccessToken(annotation);
        final OAuth2Authentication oauth2 = accessToken.oauth2();
        context.setAuthentication(oauth2);
        return context;
    }
}
class GivenAccessToken {
    GivenAccessToken(final WithAccessToken accessToken) {
        // 省略
    }
    AccessTokenEntity accessTokenEntity() {
        // 省略
    }
    private OAuth2Authentication oauth2() {
        final AccessTokenEntity accessTokenEntity = accessTokenEntity();
        final Authentication authentication = new Authentication(accessTokenEntity);
        return authentication.oauth2();
    }
}

privateメソッドに一度抽出しているが、これを飛ばしてメソッド抽出+メソッドを別クラスへ移動することはできない(っぽい)