Java設計モデル(十)単一職責原則(SRP)


単一職責原則(Single Responsibility Principle)
SRP基本概念
単一職責の原則
  • 定義:クラスの変更を引き起こす原因は、インタフェースまたはクラスと職責の関係が1つ1つに対応している必要があり、1つだけある.
  • 難点:職責の区分:
  • 異なるシナリオと生産環境の下で、私たちの職責の細分化は異なる(職責の単一の相対性)
  • である.
  • 単一職責原則は、インタフェースが優れているか否かを評価する基準を提案するが、職責と変化原因は測定不可能であり、プロジェクトによって環境によって異なる(測定不可能性)
  • である.
  • のメリット:
  • クラスの複雑さの低減:各クラスまたはインタフェースは単一の職責のみを実現し、定義が明確である
  • 可読性の向上:定義が明確で、自然に高いコード可読性をもたらす
  • メンテナンス性の向上:コードの可読性が強く、理解しやすく、自然にメンテナンスが便利で、職責が単一であるためクラス間の結合度が低いため、修正しやすい.
  • の拡張性はより良い:新しい職責があれば拡張する必要があり、対応するインタフェースを継承して新しい実現を実現するだけでよい.


  • 例としてSRP
    オブジェクト向けのプログラミングはインタフェース向けのプログラミングを推奨するため、私たちが対外的に暴露する方法もインタフェースの形式で定義することが望ましい.さらに具体的なクラスによって実現され、多くのメリットは言うまでもなく、簡単なシーンに基づいて設計され、単一の職責のメリットを体現する.
    シーンの定義
    例えばPearは電子製品メーカーで、pad、phone、watchなどの設備を生産しなければならないが、いくつかの重複機能があり、それぞれ設計すれば、明らかにお得ではない.インタフェースの定義では、機能区分に基づいて単一の職責のインタフェースを設定することができる.
    インタフェースの定義
    //      
    interface Callable{
        void call ();
    }
    
    //      
    interface Touchable{
        void touch();
    }
    
    //      
    interface MessagePromptable{
        void prompt();
    }
    
    //      
    interface KeyBoardMatchable{
        void match();
    }

    インタフェースを実装するクラスは依然として単一の職責である
    class StandardCall implements Callable{
    
        @Override
        public void call() {
            System.out.println("Call to somebody!");
        }
    }
    
    class StandardTouch implements Touchable{
    
        @Override
        public void touch() {
            System.out.println("touch to press the button!");
        }
    }
    
    class StandardPromt implements MessagePromptable{
    
        @Override
        public void prompt() {
            System.out.println(" someone contact to you,sir!");
        }
    }
    
    class StandardMatch implements KeyBoardMatchable{
    
        @Override
        public void match() {
            System.out.println("The keyBoard is ready to work!");
        }
    }

    製品の生産
  • 既存の技術に基づいて携帯電話を生産する場合は、電話、タッチスクリーン制御、メッセージ通知が必要です.
  • //                    
    class MyPhone implements Callable,MessagePromptable,Touchable{
    
        //           ,      
        private Callable caller = new StandardCall();
        private MessagePromptable prompter = new StandardPromt();
        private Touchable toucher = new StandardTouch();
    
        @Override
        public void call() {
            caller.call();
        }
    
        @Override
        public void prompt() {
            prompter.prompt();
        }
    
        @Override
        public void touch() {
            toucher.touch();
        }
    }
    
    public class SRPTest {
        public static void main ( String [] args ){
            MyPhone phone = new MyPhone();
            phone.call();
            phone.prompt();
            phone.touch();
        }
    }
  • もし私たちが新しい携帯電話を出す必要があるならば、しかし私たちはただ新しいコール技術を持っているだけで、それではこの技術を実現する時Callableインターフェースを継承するだけで、それから前の携帯電話のCallableの具体的な凶悪な事件類を新しい技術に変えるだけで、1行のコードを直すだけで、素晴らしいと感じますか?職責の単一性は、既存のクラスの変更に与える影響に制約があります.
  • では、もし私がPadを生産したいなら、同じように、既存の技術に搭載すればいいのではないでしょうか.Pad類は依然として単一の統合技術で製品を形成する職責であり、製品に統合され、技術を開発する職責が分離され、私たちの類の開拓に
  • をもたらしました.
    class MyPad implements Touchable,KeyBoardMatchable{
    
        Touchable toucher = new StandardTouch();
        KeyBoardMatchable matcher = new StandardMatch();
    
        @Override
        public void match() {
            toucher.touch();
        }
    
        @Override
        public void touch() {
            matcher.match();
        }
    }

    まとめ
    上記の例では、単一のインタフェースが実装クラスを提供すると、クラスの数が膨大になり、使いにくいため、いくつかの機能を統合することができます.簡単に言えば、
    単一の職責の原則に対して、インタフェースは必ず単一の職責をやり遂げなければならなくて、類の設計はできるだけ1つの原因だけが変化を引き起こすことをやり遂げます
  • の次の例では、私たちのインタフェースは依然として単一の職責を果たしていますが、電話に出る機能とダイヤルする機能は往々にして区別できません.彼らは同時に変化するので、2つのインタフェースを同時に継承する実装クラスを提供することができます.
  • class CallAndPrompt implements Callable,MessagePromptable{
    
        @Override
        public void call() {
            System.out.println("Hello, I have some thing to tell you!");
        }
    
        @Override
        public void prompt() {
            System.out.println("Hello,what do you want to tell me!");
        }
    }
    
    //                    
    class MyPhone implements Callable,MessagePromptable,Touchable{
    
        //           ,      
        private Callable caller = new CallAndPrompt();
        //                  
        private MessagePromptable prompter = (MessagePromptable)caller;
        private Touchable toucher = new StandardTouch();
    
        @Override
        public void call() {
            caller.call();
        }
    
        @Override
        public void prompt() {
            prompter.prompt();
        }
    
        @Override
        public void touch() {
            toucher.touch();
        }
    }

    上の例から、私のまとめをもっと理解するかもしれません.しかし原則というものは守らなければならないが、死守する必要はない.実際の設計ではやはり融通を学ばなければならない.結局経典の設計モードもいつもこれらの設計原則を守らないで、しかし彼らは依然として広範に実際の中に応用されて、その上表現は悪くありません