web-dev-qa-db-ja.com

単一責任原則の実装

余暇には、実際のソフトウェアの設計やアーキテクチャなどを学ぶためにCMSを設計しています。

SOLIDの原則を実行すると、「MVC」、「DRY」、「KISS」などのアイデアがほぼ適切に機能していることにすでに気づきました。それでも、まだ問題があります。単一責任の原則に関しては、2つの実装のいずれかが最良の選択であるかどうかを判断します。

実装#1:

class User
    getName
    getPassword
    getEmail
    // etc...

class UserManager
    create
    read
    update
    delete

class Session
    start
    stop

class Login
    main

class Logout
    main

class Register
    main

この実装の背後にある考え方は、すべてのユーザーベースのアクションが異なるクラスに分けられることです(適切な名前の Ravioliコード の可能性のあるケースを作成します)が、SRPに従って「ティー」になります。文字通り。

しかし、それから私はそれが少し多いと思い、この次の実装を思いついた

class UserView extends View
    getLogin //Returns the html for the login screen
    getShortLogin //Returns the html for an inline login bar
    getLogout //Returns the html for a logout button
    getRegister //Returns the html for a register page
    // etc... as needed

class UserModel extends DataModel implements IDataModel
    // Implements no new methods yet, outside of the interface methods
    // Haven't figured out anything special to go here at the moment
    // All CRUD operations are handled by DataModel 
    //   through methods implemented by the interface

class UserControl extends Control implements IControl
    login
    logout
    register
    startSession
    stopSession

class User extends DataObject
    getName
    getPassword
    getEmail
    // etc...

これは明らかにまだ非常に組織化されており、依然として非常に「単一責任」です。 Userクラスは、データを操作してからUserModelに渡してデータベースに保存できるデータオブジェクトです。すべてのユーザーデータレンダリング(ユーザーに表示されるもの)はUserViewとそのメソッドによって処理され、すべてのユーザーアクションはUserControlの1つのスペースにあります(さらにCMSに必要な自動化されたものもあります)ユーザーのログインを維持するため、またはユーザーがログインしないようにするためです。)個人的には、この実装に問題があるとは考えられません。

私の個人的な感情では、どちらも事実上正しいと思いますが、どちらがどちらを維持して拡張するかは、人生が進むにつれて簡単に決定できません(実装#1に傾いているにもかかわらず)。

では、あなたたちはどうですか?これについてどう思いますか?どちらがいいですか?どちらの設計でも、その原則のどの基本(またはその他のニュアンス)を見逃していますか?

5
Mike S

私は常に、単一責任の原則を原則よりも哲学であると考えてきました。

ロバートC.マーチン(ボブおじさん) 単一責任の原則を言い換えます(PDFにリンクされています)

クラスが変更される理由は複数あるべきではありません

あなたがあなたの投稿を得た返信から引用しました。

SPRを和らげようとするときは、目的ではなく実装に焦点を合わせます。

大きな間違い。

SRPについての私の理解はこれです。追加によって実装の責任が曖昧になった場合は、焦点を再検討する必要があります。

私にとって、それはすべて目的間の関係についてです。

確かに、ユーザーは実行するアクションに関して認証および承認される必要がありますが、認証と承認はユーザーから分離する必要があります。

とにかく非ユーザーを認証/認証しようとしているのではありませんか?

したがって、クラスの責任が目的を超える場合は、実装の分割を検討する必要があります。結局のところ、デザインパターンにも目的があります。

機会があれば [〜#〜] grasp [〜#〜] を見てください。

5
Schalk

「単一責任の原則」は「単一機能の原則」と同じではありません

多くの場合、これを可能な限り宗教的に行おうとすると、クラスを少し「壊す」傾向がありますが、各オブジェクトが他のオブジェクトについて何かを知る必要があるため、SRPに違反する可能性があります。変更のため。

上記のクラスの意図についてはあまり明確ではありませんが、ここにいくつかのポイントがあります-

  • loginlogoutが互いに完全に独立できるかどうか、またどちらかがsessionから独立できるかどうかはわかりません

  • loginlogoutをクラスと見なすのか、メソッドと見なすのか、そしてその理由はわかりません。

  • UserManager _createが別の形式new user()かどうかわからない

私はすべてを本当に理解していないので、私は多くの点で完全に間違っていると思います。 2番目のものは最初のものより少し良いですが、私はまだ間違っているかもしれません。

しかし、それがまさにポイントです。クラスを見ると、意図が非常に明確であることがわかります。ここでは、SRPがうまく機能していないことを示しています。

1
Dipan Mehta

私がこれを行うのが好きな1つの方法は、構造全体を無視してクラスの構築を開始することです。

そして、3の一般的なルールに従います。

  • 3つ以上のパブリック関数を使用することになった場合は、それらを別々のクラスに分割してください。
  • 3つを超える内部変数が発生する場合は、個別のクラスに分割してください。
  • 関数に3つ以上の機能行が含まれることになった場合は、それを異なる関数に分けてください。

これにより、構造が正しいかどうかを心配する必要がなくなります。あなたはあなたの開発に流動的であることができます。このコーディングプロセスは、単体テストがある場合や一般にTDDを実行する場合に簡単ですが、100%必須ではありません。それはまたあなたの脳のためのいくらかの精神的な頭上を取り除きます。

時々、構造について非常に心配し、それについて非常に苦しむことがわかります。時間が経つにつれて、構造に執着しすぎて、必要なときに適応する気がなくなります。

0
Bob