CleanCode TIL (2022.02.15)


DAY 23
🔖 今日読む範囲:11.システム(194~205 p)
🤓 本の中で覚えたい内容
もし都市を建てるなら?
  • 都市で大きな絵を描いている人もいれば、小さなことに集中している人もいます.
  • 適切な抽象化とモジュール化→大図は分からないが、個人管理のコンポーネントは効率的に
  • に戻ることができる.
  • クリーンコード→低抽象レベルから関注点
  • を分離
  • より高い抽象レベルからより高いシステムレベルへ
    システム作成とシステム使用を分ける.
    製作と使用は大きく異なる
  • 作成(準備手順)
  • APPオブジェクトを作成し、
  • に関連付けます.
  • (ランタイムロジック)の使用
  • 準備完了後の論理
  • ちえんイニシャルほう
    public Service getService() {
        if (service == null)
            service = new MyServiceImpl(...); // 모든 상황에 적합한 기본값일까? 
        return service;
    }
  • の利点
  • 実際に必要になる前にオブジェクトを作成しないため、負荷を減らす→APP起動時間を短縮する
  • nullポインタ
  • は返さない.
  • 問題
  • getServiceメソッドは、MyServiceImplとコンストラクション関数に依存して
  • を買収することを明確にしています.
    依存性の問題を解決しない限り、コンパイルできません.
  • MyServiceImplが恐ろしいオブジェクトである場合、呼び出す前にテストオブジェクトのみをサービスフィールド
  • に割り当てる必要があります.
  • オブジェクト作成ロジックが混在しているため、単一責任原則
  • に違反する.
  • MyServiceImplすべての状況に適合するかどうか不明
  • を頻繁に使用するとモジュール化の度合いが低下し、冗長性
  • が増加する.
    Main分離技術
  • を生成する関連コードはmainまたはmain呼び出しのモジュールであり、
  • である.
  • 残りのシステムは、すべてのオブジェクトが作成され、関連付けられていると仮定します.
    こうじょう
  • オブジェクトがいつ作成されるかは、APPによって決定する必要がある
  • Order Processing APPではLineItemの作成方法はわかりませんが、インスタンスの作成時点
  • を制御できます.
  • の作成方法MainのLineItemFactory Implementationで技術
  • を使用する.
    依存性注入
    依存性管理において
  • 制御逆転技術を採用するメカニズム
  • 制御逆転:1つのオブジェクトの補助責任を新しいオブジェクトに転嫁→SRP成立
  • 依存性管理:オブジェクトは依存性自体をインスタンスとする責任を負いませんが、他の専門的な責任メカニズム
  • に渡す必要があります.
  • は、システム全体にわたって初期設定が必要であるため、
  • を主容器または特殊容器に渡す.
  • eg)JNDI検索
    MyService myService = (MyService)(jndiContext.lookup("NameOfMyService"));
  • オブジェクトは、ディレクトリサーバに名前を提供し、名前に一致するサービス
  • を要求する.
    依存性の問題を動的に解決するには、返されるオブジェクトのタイプを制御する必要はありません.
  • クラスの依存性は完全に受動的な
  • である.
  • ではなく依存注入法を使用して、設定者または作成者パラメータ
  • を提供する.
  • eg)スプリングフレーム
  • オブジェクト間の依存性はXMLファイルで
  • と定義されています.
  • コードは、特定のオブジェクト
  • を名前で要求する.
  • 初期化技術も依存注入を用いることができる
  • ほとんどは、計算を遅延または最適化するためにファクトリを呼び出す方法またはエージェントを作成する方法を提供します.
  • eg)計算遅延技術、最適化技術
  • 拡張
  • システムアーキテクチャは、
  • を事前に計画する必要がある.
  • のライフサイクルが短く、アーキテクチャが絶えず発展しています.
    管理
  • 適切に分離された関心点
  • 横断的な注目点
  • の永続性のような注目点は、APPの自然オブジェクト境界
  • を越えている.
    すべてのオブジェクトを同じ方法で全体を使用する必要があります.
  • 特定のDBMSは、ファイルを単独で使用し、テーブルとカラムは同じ命名規則を有し、トランザクションの意味が一致する
  • である.
  • 展望向けプログラミング:観点向けプログラミング
  • 特定の注目点をサポートするには、システム内の特定のポイントの動作を変更する必要があります.
  • は、永続的に保存するオブジェクトと属性
  • を宣言します.
  • 永続性責任を永続性フレームワーク
  • に委任する.
  • 動作を
  • に変更し、フレームワークターゲットコードに影響を与えません.
    Javaエージェント
  • メソッド呼び出しは、単純な場合に非常に適している
  • クラスエージェントには、CGIB、ASM、Javaなどの
  • バイトコード処理ライブラリが必要です.
    // Bank.java (패키지 이름을 감춘다)
    import java.util.*;
    // 은행 추상화
    public interface Bank {
        Collection < Account > getAccounts();
        void setAccounts(Collection < Account > accounts);
    }
    // BankImpl.java 
    import java.util.*;
    // 추상화를 위한 POJO("Plain Old Java Object") 구현
    public class BankImpl implements Bank {
        private List < Account > accounts;
        public Collection < Account > getAccounts() {
            return accounts;
        }
        public void setAccounts(Collection < Account > accounts) {
            this.accounts = new ArrayList < Account > ();
            for (Account account: accounts) {
                this.accounts.add(account);
            }
        }
    }
    // BankProxyHandler.java 
    import java.lang.reflect.*;
    import java.util.*;
    // 프록시 API가 필요한 "InvocationHandler"
    public class BankProxyHandler implements InvocationHandler {
        private Bank bank;
        public BankProxyHandler(Bank bank) {
            this.bank = bank;
        }
        // InvocationHandler에 정의된 메서드
        public Object invoke(Object proxy, Method method, Object[] args)
        throws Throwable {
            String methodName = method.getName();
            if (methodName.equals("getAccounts")) {
                bank.setAccounts(getAccountsFromDatabase());
                return bank.getAccounts();
            } else if (methodName.equals("setAccounts")) {
                bank.setAccounts((Collection < Account > ) args[0]);
                setAccountsToDatabase(bank.getAccounts());
                return null;
            } else { ...
            }
        }
        // 세부사항은 여기에 이어진다.
        protected Collection < Account > getAccountsFromDatabase() { ...
        }
        protected void setAccountsToDatabase(Collection < Account > accounts) { ...
        }
    }
    // 다른 곳에 위치하는 코드
    Bank bank = (Bank) Proxy.newProxyInstance(Bank.class.getClassLoader(),
        new Class[] {
            Bank.class
        },
        new BankProxyHandler(new BankImpl()));
  • エージェントパッケージインタフェースライブラリとビジネスロジックを実現するPOJO BankImplを定義します.
  • エージェントAPI
  • を使用して、エージェントへのダンプの銀行メソッドを実装
  • BankProxyHandler java Replication APIを使用して対応するBankImplメソッド
  • にマッピング
  • エージェントコード量が多く、システム単位で運転点を指定するメカニズム
  • は提供されない.
    🤔 浮想
  • は、動的に入力された接続情報を用いてDB接続を確立し、プール依存性を注入するシステムを実施している.本を読む前は難しそうに見えましたが、製作と使用の分離のためには、これが必須だと知っていて、工場方式で進めば、問題解決できるはずです.
  • 🔎 n.問題

  • 📝 感想3行ダイジェスト
  • システム作成と使用分離(主分離、工場、依存注入)
  • 観点向けプログラミング(AOP):特定の注目点に対して、特定の操作方式で一致しなければならない、
  • Javaエージェント:特定の観点を分離できますが、コード量が多く、実行ポイント
  • を指定できません.