Design Principles

16334 ワード

以前のプログラミングモードでは、コードを
今回の設計原則は,それよりも高度な概念クラスおよび関数の中間段階の構造の原則を記述した.
目標は以下の通り.(いいものがある感じ…)
  • 変更可能
  • を再利用
  • コードの可読性
  • Single Responsibility Principle


    この原則が生み出す背景や必要性で原則を説明する.

    まず上の写真を見ると、Employeeなどを集中的に使っている関係者が3人いました.
    誰もが1つの機能が必要です.それはすべて1つのクラスに集中することです.
    実際、修正がなければ、これ以上悩む必要はありませんが、私たちのソフトウェアはソフトウェアでしょう.
    次に、この場合に新しい機能を追加すると仮定します.
  • CFOは給与計算時に奨励制度を導入し、Employee等級を修正した.
  • COOもreport関数を変更する必要があるため変更されます.
  • 同時に2人が1つのクラスを修正しているのではないでしょうか.
    もちろん、彼ら二人もこれが同時に修正されたことを知らない.
    あとはVCS合併の時にわかるでしょう.問題はこの時に起きた.
    マージを試行中に問題が発生した場合、誰が修正して解決しますか?
    著者はこの部分が問題だと言った.
    したがって,classを2人で同時に修正しないためには,CFOはCFOを必要とするファイルのみを修正することができる.CTOはCTOが必要なファイルのみを修正します.
    衝突を防ぐことで解決するという.
    SRP原則の構成は以下の通りです.

    簡単に言えば、Employee Facadeクラスにはコードがなく、サブクラスに3つのクラスを作成して委任します.
    各参加者は、クラスを変更すればよいと考えています.マージ中の競合を心配する必要はありません.変更を知る必要はありません.
    まとめてみると、「SRPの原則は、1つのモジュールを1つの単位の参加者によって変更/アクセスさせることです」.

    Open Closed Principle


    次のコードは例として問題を考慮します.
    struct Book { 
    	let id: String 
    	let title: String 
    	let author: String 
    	let rentalPrice: Int 
    } 
    
    struct Video { 
    	let id: String 
    	let title: String 
    	let director: String 
    	let rentalPrice: Int 
    } 
    
    //해당 클래스는 렌탈 가격을 계산해주는 기능을 함수이다.
    class RentalPriceCalculator {
     var totalRentalPrice: Int { 
    		var result = 0 
    		result += self.books.reduce(0, { $0 + $1.rentalPrice })
    		result += self.videos.reduce(0, { $0 + $1.rentalPrice }) 
    		return result 
    	} 
    
    	func addBook(_ book: Book) { 
    		self.books.append(book) 
    	} 
    
    	func addVideo(_ video: Video) { 
    		self.videos.append(video) 
    	} 
    
    	private var books = [Book]() 
    	private var videos = [Video]() 
    }
    
    ここで将棋ゲームを追加したいなら
    RentalPriceCalculatorクラスを再変更する必要があります.
    著者は、上司のモジュールを変更したり変更したりするのは危険なことだと話しています.
    サブモジュールの変化により親モジュールに変更するのは危険です.
    したがって、子モジュールは拡張できますが、親モジュールを変更(開く)必要はありません.
    これがOCPの概念です.
    では、OCP保護の次のコードを見てみましょう.
    protocol RentalItem { 
    	var id: String { get } 
    	var rentalPrice: Int { get } 
    }
    
    class RentalPriceCalculator { 
    	var totalRentalPrice: Int { 
    		return self.items.reduce(0, { $0 + $1.rentalPrice }) 
    	} 
    
    	func addRentalItem(_ item: RentalItem) {
    		 self.items.append(item) 
    	}
    
    	private var items = [RentalItem]() 
    }
    
    リースアイテムを追加するためにプロトコルに従った構造のみを作成しても、RentalPriceCalculatorは変更されません.
    したがって,OCPは良好に保護されているといえる.

    Liskov Subsitution Principle



    上記の問題を解決するために、LSPの原則が必要です.
    SquareはRectangleのサブタイプとしては適していません.
    Rectangleでは、幅の高さは独立して変更する必要があります.ただしSquareの幅の高さは同じでなければならないので、常に一緒に変更する必要があります.
    したがって、LSPによれば、上述の関係は正しくない
    上記の構造を維持しながら問題を解決するには、if文を使用してタイプをチェックし、対応する関数を呼び出す必要があります.平行四角形などのタイプが増加した場合、どのように対応しますか?
    上記の問題を起こさなければ
    Shape → Square
       → Rectangle
    上記のような垂直拡張ではなく横方向から解決すべきである.
    著者らは,これは解決策であり,常に上下置換可能な状態を保たなければならないと考えている.

    Interface Segregation Principle


    インタフェースに従うオブジェクトが不要なオブジェクトに従うと、どのような問題が発生するかの例を見てみましょう.
    protocol MediaProtocol {
    		var isMute: Bool { get set }
    
    		func play()
    		func load()
    }
    
    //여기서는 별 문제없이 모든 인터페이스 기능을 잘 사용하고 있다.
    class OurVideoView: MediaProtocol {
    	var isMute: Bool {
    		get { return self.player.isMuted }
    		set { self.player.isMuted = newValue }
    	}
    
    	func play() {
    			//play action
    	}
    
    	func load() {
    			//load something
    	}
    }
    
    //아래의 예시에서는 슬슬 모든 기능을 사용하지 않고 형식에 맞추기 위해 인터페이스를 사용하는데....
    class YoutubeVideoView: MediaProtocol {
    	var isMute = false //미사용
    	
    	func load() {
    		//load action
    	}
    
    	func play() {
    		//미사용
    	}
    }
    
    //나중에 추가기능으로 음소거일 경우 재생을 하지 않도록하는 기능을 추가
    func showMedia(_ view: MediaProtocol) {
    		guard !view.isMute else { return }
    		view.load()
    }
    //드디어 문제가 터졌다 우리는 YoutubeViewView는 무조건 isMute를 false로 구현해놓지  않았는가.
    //YoutubeVideoView는 절대 재생이 안되는 문제가 생긴다.
    

    Dependency Inversion Principle


    依存性逆転法則
    実はSOLID概念の中で最も核心的な概念と言える.
    依存性を逆方向の逆転と理解するのは、最初は理解しにくい.
    その意味よりも,抽象的なインタフェースを介して直接依存関係を間接的に変える考えがあれば,より理解しやすいようである.
    では、DIPで解決する問題を見てみましょう.

    これは私たちが考えやすい関係です.
    直接層ごとに関係を築き、強く縛られる.
    したがって、最下位レベルのアプリケーション・ツール・レイヤを変更すると、変更がポリシー・レイヤに影響を及ぼす可能性があります.
    複数の部分が修正されたリスク指数に従います.
    DIPに従う仕組みを見てみましょう.

    サブレイヤと親レイヤの間のインタフェースは抽象に依存します.
    最下位の「機械層」として、ポリシー・サービス・インタフェースのみに従うと、無数の変形が発生しても影響を及ぼすことは少ない.
    作者はDIPを無条件に守るのは実は難しいことだと言っています.
    しかし,頭の中に上記の背景とソリューションがあることが分かれば,アーキテクチャを作成することとしないこととでは大きな違いがある.
    作者が実際のDIPを守るためのガイドを見てみましょう.
  • 可変クラスは参照しないでください.
  • 可変クラスに従わないでください.
  • クラスの関数
  • を上書きしないでください.
  • の変動性の大きいものは言及しないでください...
  • 全体的なルールから見ると,変動性の大きいクラスと非変動性の大きいクラスを区別し,これらのクラスとの関係は直接継承や宣言ではなくインタフェースを利用してアクセスするという意味のようである.
    参考文献
    SWIFTコードを使用してSOLIDの原則を理解する
    Spring例のSOLID DIP-Yun Blog|テクニカルブログ
    Dependency inversion principle