Java Refactoring—10、Null異常処理が元の機能と異なることを改善


誰でも簡単に古いコードをクリーンアップコードに変換できます
これは上の本を見て整理した文章です.

元の機能とは異なるNull例外処理の改善


Nullの繰返し処理はコードの独立性と信頼性を低下させた.
  • プログラムの実行中、受信したオブジェクトが空の場合、ブランチ文を使用してオブジェクトを確認し、異常論理を実行します.
  • オブジェクトのブランチ文と異常処理ロジックがコードのあちこちで繰り返されていることを無意識に確認する.
  • ほとんどのオブジェクトが渡された場所では、オブジェクトが空であることがわかります.
  • の送信時にオブジェクトがNullであることを予め知る、異常処理を実行するオブジェクトに転送すると、
  • .
  • を受信した場所では、少なくとも1つの例外処理が減少します.
  • Nullに対して異常処理を行うオブジェクトをNullオブジェクトと呼ぶ.
  • オブジェクトがNullの場合、あるオブジェクトに例外処理が委任されると、論理はオブジェクトによる論理実行にのみ集中する、
  • .
  • コードの簡潔性と可読性を向上させることができる.
  • 改善方向


    オブジェクトを渡すクラスに例外を処理させます。


    質問の答え


    Nullオブジェクトを個別に定義して使用して、単純なNullチェックを行う必要がありますか?
  • 使い捨てならやらなくてもいいです.ただし、Nullチェックが重複して発生したり、個別のロジックを追加して異常処理を行う場合.
  • の場合、Nullオブジェクトを個別に定義すれば、元の機能に集中することができ、コードの読みやすさを向上させることができる.
  • は、何気なくNull確認の部分を抜けて補足するコードになる可能性もあります.
  • 渡されたオブジェクトがNullであるかどうかを確認し、直接異常処理を行うと問題になりますか?
  • Null処理のもう一つの問題は、インタフェースを使用するオブジェクトがNullを処理しなければならないことである.
  • は予想外の機能を含み、単一責任の原則に反している.
  • Nullオブジェクトの核心は、Nullの状況を直接処理するのではなく、インタフェースを定義したオブジェクトとして委任することである.
  • 古いコード



    SNWriterクラス

    public class SnsWriter {
        private List<String> accounts;
    
        public SnsWriter(List<Account> accounts) {
            this.accounts = accounts;
        }
    
        public void write(String message, String link, String imagePath) {
            for(Account account : accounts) {
                Writer writer = account.getWriter();
    
                // Writer가 Null인 SNS에 대해서는 재인증 요청
                if(writer != null) {
                    writer.write(message, link, imagePath);
                } else {
                    // 사용자에게 인증 요청
                    new Author().requestAuth();
                }
            }
        }
    }

    アカウントインタフェース

    public interface Account {
        // 해당 SNS에 필요한 게시물 등록 객체 가져오기
        public Writer getWriter();
    }
    
    
    

    FaceAccountクラス

    public class FaceAccount implements Account {
        private String authKey;
    
        public FaceAccount(String authKey) {
            this.authKey = authKey;
        }
    
        @Override
        public Writer getWriter() {
            if(authKey != null) {
                // 인증 정보가 있으면 게시물 등록 객체 전달
                return new FaceWriter(authKey);
            } else {
                // 인증 정보가 없으면 Null 전달
                return null;
            }
        }
    }

    Writerインタフェース

    public interface Writer {
        public void write(String message, String link, String imagePath);
    }

    FaceWriterクラス

    public class FaceWriter implements Writer {
        private final String authKey;
    
        public FaceWriter(string authKey) {
            this.authKey = authKey;
        }
    
        @Override
        public void write(String message, String link, String imagePath) {
            // 게시물 등록
        }
    }
    上記のコードの問題
    1.SNWriterオブジェクトには、Accountによって渡されたWriterがNullであるかどうかを決定し、例外処理を行う論理が含まれます.

    従来のコード改善プロセス



    Nullオブジェクトの定義

  • SNWriterのNull処理をNoauthWriterに移動し、NoauthWriterを使用します.wirte()がユーザ検証を要求する論理
  • を定義する

    NoauthWriterクラス

    public class NoAuthWriter implements Writer {
        @Override
        public void write(String message, String link, String imagePath) {
            // 사용자에게 인증 요청
            new Author().requestAuth();
        }
    }

    Account実装のgetWriter()の変更

    public class FaceAccount implements Account {
        private String authKey;
    
        public FaceAccount(String authKey) {
            this.authKey = authKey;
        }
    
        @Override
        public Writer getWriter() {
            if(authKey != null) {
                // 인증 정보가 있으면 게시물 등록 객체 전달
                return new FaceWriter(authKey);
            } else {
                // Null - NoAuthWriter
                return new NoAuthWriter();
            }
        }
    }

    テストコードの生成

    public class AccountTest {
        @Test
        public void testGetWriter() throws Exception {
            // Given
            // 인증 정보가 없는 계정을 설정
            FaceAccount faceAccount = new FaceAccount(nul);
    
            // When
            Writer writer = faceAccount.getWriter();
    
            // Then
            // Null Object로 반환되므로 Null이 아니다
            Assert.assertNotNull(writer);
    
            // 의도한 Writer와 동일한지 확인
            Assert.assertEquals(NoAuthWriter.class, writer.getClass());
        }
    }

    SNWriterの変更

    public class SnsWriter {
        private List<String> accounts;
    
        public SnsWriter(List<Account> accounts) {
            this.accounts = accounts;
        }
    
        public void write(String message, String link, String imagePath) {
            for(Account account : accounts) {
                Writer writer = account.getWriter();
                 writer.write(message, link, imagePath); 
            }
        }
    }

    レガシーコードの改良


    NoauthWriterクラス

  • ライタがNullであるときに扱う異常論理のクラスを抽出し、改良前のSNWriterに含まれるNull処理論理
  • を実現した.

    Accountクラス

  • 認証情報がない場合はNoauthWriterを返します.
  • 改善前にNullを返しますが、Nullを置き換えるオブジェクトを返すように変更しました.
  • SNWriterクラス


    ライターは、
  • Accountオブジェクトが返すWriterオブジェクトがNullであるかどうかを決定する必要はありません.writer()を実行します.
  • Accountオブジェクトはnullを返さないのでnullをチェックする必要はなく、異常論理も戻りオブジェクトとして実行できます.
  • まとめとまとめ


    返されたオブジェクトがNullの場合、他の処理部をオブジェクトとして処理できるようになりました.
  • Nullオブジェクトは、例外処理
  • にのみ使用する.
  • の機能を実行するために個別のオブジェクトを定義するのは容易ではないかもしれませんが、Nullオブジェクトの最大の利点は、コード内でNullを予測し、異常論理を他の場所に移動することです.
  • は、コードを従来の機能を実行できるように改良した.
  • Nullオブジェクトモードを使用して改善された考え方の流れ

  • 入力オブジェクトがNullである場合の処理ロジック
  • があるかどうかを検証する.
  • 送信先にもNullを渡すコード
  • があることを検証する.
  • は、Nullを処理できるオブジェクトを共同で作成します.
  • 転送オブジェクトが
  • Nullの場合、例外処理を実行するNullオブジェクトが転送されます.