IoC(制御反転)、DI(依存注入)を深く理解する

3211 ワード

について述べる
最近,設計モードやlaravelコードを見ると,制御反転や依存注入という概念に困惑し,制御反転の理解について以下の資料を探した.
コンセプト
IoC
制御反転(Inversion of Control、IoCと略す)は、コンピュータコード間の結合度を低減するために使用できるオブジェクト向けプログラミングにおける設計原則である.従来、プログラムコードによって直接操作されていたオブジェクトの呼び出し権をコンテナに渡し、コンテナによってオブジェクトコンポーネントのアセンブリと管理を実現します.「制御反転」という概念は,コンポーネントオブジェクトに対する制御権の移行であり,プログラムコード自体から外部コンテナに移行する.その中で最も一般的な方法は依存注入(Dependency Injection、略称DI)と呼ばれ、もう一つの方法は「依存ルックアップ」(Dependency Lookup)と呼ばれている.制御反転により、オブジェクトは作成されると、制御システム内のすべてのオブジェクトの外部エンティティによって、依存するオブジェクトの参照が伝達されます.依存はオブジェクトに注入されるともいえる.
概念で説明されているように、制御反転とは具体的にどの制御が反転されたかを指すが、実は私が理解している制御反転とは、プログラムが制御するオブジェクトの制御権が容器に渡され、この容器が各モジュールの解結合を実現する鍵である.IoCはただ1種の設計思想で、主に実現します:
  • 依存ルックアップ(Dependency Lookup):コンテナはコールバックインタフェースとコンテキスト環境をコンポーネントに提供します.
  • 依存注入(Dependency Injection)
  • 依存注入についてもう一度お話しします.
    DI
    ソフトウェアエンジニアリングでは,依存注入は依存設計モードを解決するために制御反転を実現する.1つの依存関係とは、利用可能なオブジェクト(すなわち、サービスプロバイダ)を指す.依存注入は、使用する依存オブジェクト(すなわちクライアント)に依存を渡すものです.このサービスはクライアントの状態の一部になります.本設計モードの基本的な要件は、クライアントがサービスを確立または検索することを許可するのではなく、クライアントにサービスを伝達することである.
    以上はwikipediaにおける依存注入に対する理解であり,以下では実際の例を用いて詳細に説明する.
    例を挙げる
    共通のユーザーログインベースクラスを設計し、複数のプラットフォームのユーザーログインをサポートできる最悪の書き方は、
    /**
     * A     
     **/
    class User_A_Login
    {
        public function checkALogin(){
            
        };
    }
    
    /**
     * B     
     **/
    class User_B_Login
    {
        public function checkBLogin(){
            
        };
    }
    /**
     *     
     **/
    class User_Login
    {
        public function checkLogin($userType)
        {
            if($userType = 'A'){
                $this->objAUser = new User_A_Login();
                $this->objAUser->checkALogin();
            }elseif($userType = 'B'){
                $this->objBUser = new User_B_Login();
                $this->objBUser->checkBLogin();
            }
        }
    }

    上のUser_Loginというクラスは直接クラスUserに依存している.A_LoginとUser_B_Login、次のように書けば
    
    interface User_Login_Interface
    {
        public function checkLogin();
    }
    /**
     * A     
     **/
    class User_A_Login implements User_Login_Interface
    {
        public function checkLogin(){
            
        };
    }
    
    /**
     * B     
     **/
    class User_B_Login implements User_Login_Interface
    {
        public function checkLogin(){
            
        };
    }
    /**
     *     
     **/
    class User_Login
    {
        public $userLogin;
        
        public function setUser(User_Login_Interface $user){
            $this->userLogin = $user;
        }
        
        public function checkLogin()
        {
            $this->userLogin->checkLogin();
        }
    }
    

    このようにしてコードを構築すると、我々はアイテムUser_に依存します.B_LoginまたはUser_A_Loginは関数setuser()によってクラスに注入され、呼び出し方法:
    $userLogin = new User_Login();
    $userLogin->setUser(new User_A_Login);
    $userLogin->checkLogin();

    呼び出し側はそのログインタイプの使用を制御することができ,これにより異なるログインシステムへの依存注入が完了する.新しいユーザーcを導入した場合は、cのログインクラスを書くだけです.
    /**
     * C     
     **/
    class User_C_Login implements User_Login_Interface
    {
        public function checkLogin(){
            
        };
    }

    次のことができます.
    $userLogin = new User_Login();
    $userLogin->setUser(new User_C_Login);
    $userLogin->checkLogin();

    ログイン検証を行いました.実際のコードでは、ベースクラスが非常に複雑であるため、ログインを一連の処理を行う必要があるため、ログインユーザーを追加するたびにベースクラスを変更するべきではありません.laravelのようなフレームワークは変更できません.このようにして実現される呼び出し元のカスタマイズであるはずです.