オーバーロードは、オープン/クローズの原則の例ですか?


12

ウィキペディアによると

「ソフトウェアエンティティ(クラス、モジュール、関数など)は拡張のために開かれている必要がありますが、変更のために閉じられている必要があります」

関数という言葉が目を引きましたが、メソッドのオーバーロードを作成することは、オープン/クローズの原則の一例とみなすことができると思いますか?

例を説明しましょう。サービスレイヤーにメソッドがあり、ほぼ1000か所で使用されていることを考慮してください。メソッドはuserIdを取得し、ユーザーが管理者であるかどうかを判断します。

bool IsAdmin(userId)

ここで、userIdではなくユーザー名に基づいて、ユーザーが管理者であるかどうかを判断する必要があると考えてください。上記のメソッドのシグネチャを変更すると、1000箇所でコードが破損します(関数は修正のために閉じる必要があります)。したがって、ユーザー名を取得するオーバーロードを作成し、ユーザー名に基づいてuserIdを見つけ、元のメソッドを見つけることができます。

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

このように、オーバーロードを作成して機能を拡張しました(機能は拡張に対して開かれている必要があります)。

それはオープン/クローズド原則の例ですか?

回答:


5

私は個人的にwikiステートメントをこのように解釈します:

  • クラス:クラスとオーバーライドを継承するか、気軽に 及ぶその機能を、しかし、元のクラスは、それによってハックしていない変更、それが何をしますか。
  • モジュール(たとえばライブラリ)の場合:元のモジュールをラップし、機能を使いやすいバージョンにマージするか、元のモジュール を追加機能で拡張する新しいモジュール/ライブラリを自由に記述できますが、元のモジュールは変更しないでください
  • 関数(クラスメソッドではなく静的関数)の場合:あなたの例は私にとって合理的です。新しいIsAdmin(string)内で元のIsAdmin(int)関数を再利用します。オリジナルは変更されず、新しいfuncは機能を拡張します。

しかし、足元のショットは、コードがIsAdmin(int)が存在する「cUserInfo」クラスを使用している場合、本質的にルールを破ってクラスを変更しているということです。悲しいことに、新しいクラスcUserWithNameInfoを作成し、パブリックcUserInfoクラスを作成し、そこにIsAdmin(string)オーバーライドを設定した場合にのみ、ルールが保持されます。私がコードベースを所有しているなら、私は規則に従わないでしょう。bollocksと言って、提案された変更を行うだけです。


3

まず、あなたの例は残念ながら不自然です。不必要なダブルゲットを引き起こすので、現実の世界では決してそうすることはないでしょう。または、さらに悪いことに、ユーザーIDとユーザー名はある時点で同じタイプになる可能性があるためです。のではなく

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUser(userid);
    return user.IsAdmin();
}

public bool IsAdmin(string username)
{
    int userId = UserManager.GetUser(username).Id;
    return IsAdmin(userId);
}

本当にそのクラスを拡張する必要があります。

public bool IsAdmin(int userid)
{
    User user = UserManager.GetUserById(userid);
    return user.IsAdmin();
}

public bool IsUsernameAdmin(string username)
{
    User userId = UserManager.GetUserByName(username);
    return user.IsAdmin();
}

一貫性を保つために、最初のメソッド名をさらにリファクタリングし、IsUserIdAdminに変更することもできますが、必須ではありません。ポイントは、新しいメソッドを追加し、呼び出しコードが破損しないことを保証することで、クラスが拡張可能であることを発見したということです。または、言い換えると、拡張開かれています。

そして、ここにオープンクローズド原則があります。コードの一部を拡張し、代わりに変更する必要があることに気付くまで(コードに伴うリスクが増大するまで)、コードどの程度適合しているかを実際に知ることはありません。しかし、経験を積むと、予測することを学びます。

以下のようアンクルボブ氏は述べています(強調鉱山):

閉鎖は完了できないため、戦略的でなければなりません。つまり、設計者は、設計を終了する変更の種類を選択する必要があります。これは経験に由来するある程度の予知を必要とします。経験豊富なデザイナーは、さまざまな種類の変更の可能性を判断するのに十分なほどユーザーと業界を熟知しています。次に、最も可能性の高い変更に対して、オープンクローズド原則が呼び出されるようにします。


良い説明をありがとう。しかし、ここでは1000回の往復または1回の往復を取得することは重要ではありません。したがって、現時点でのパフォーマンスを忘れましょう。ただし、同じ名前で異なる入力パラメーターを使用して別のメソッドを追加したため、クラスを拡張することも行いました。しかし、ボブおじさんからの引用に本当に感謝しています。+1。;)
Saeed Neamati

@SaeedNeamati:私が言っていた点は、既存のメソッドを使用するメソッドを追加する、クラスが拡張に対して開かれているかに関係なく、完全に独立したメソッドを追加するかどうかは関係ないということです。しかし、それを実現するために既存のメソッドインターフェイスを変更する必要がある場合は、変更する必要はありません。
pdr

2

開閉原理に準拠するモジュールには、2つの主要な属性があります。

  1. それらは「Open For Extension」です。これは、モジュールの動作を拡張できることを意味します。アプリケーションの要件の変更に応じて、または新しいアプリケーションのニーズを満たすために、モジュールを新しい異なる方法で動作させることができること。
  2. それらは「修正のために閉鎖」されています。このようなモジュールのソースコードは侵害されています。誰もソースコードを変更することはできません。
  1. メソッドをオーバーロードすることにより、既存のモジュールの機能を拡張し、アプリケーションの新しいニーズに対応します

  2. 既存のメソッドに変更を加えていないため、2番目のルールに違反していません。

元の方法を変更できないようにすることに関して、他の人が言わなければならないことを聞いてみたいです。はい、適切なアクセス修飾子を配置してカプセル化を強制できますが、他に何ができますか?

参照:http : //www.objectmentor.com/resources/articles/ocp.pdf


1

オープンクローズド原則は目標であり、理想的なケースであり、必ずしも現実ではありません。特に古いコードをリファクタリングする場合、最初のステップは多くの場合、OCPを可能にするための大幅な変更です。原則の根本は、動作するコードがすでに機能していることであり、変更するとバグが発生する可能性があります。したがって、最良のシナリオは、既存のコードを変更せず、新しいコードを追加することです。

しかし、という関数があったとしましょうBigContrivedMethod(int1, int2, string1)BigContrivedMethodthing1、thing2、およびthing3の3つのことを行います。この時点で、BCMを再利用することはおそらく困難です。(可能であれば)それをリファクタリングContrivedFunction1(int)ContrivedFunction2(int)ContrivedFunction3(string)あなたがより簡単に組み合わせることができることを3つの小さな、より集中する方法を提供します。

そして、それがメソッド/機能に関するOCPの鍵です:構成。他の関数から関数を呼び出すことにより、関数を「拡張」します。

OCPは他の5つの原則、SOLIDガイドラインの一部であることを忘れないでください。その最初のものが鍵であり、単一責任です。コードベース内のすべてが実行する必要がある特定の1つだけを実行した場合、コードを変更する必要はありません。新しいコードを追加するか、古いコードを新しい方法で組み合わせるだけです。実際のコードがこのガイドラインに適合することはめったにないため、OCPを取得する前にSRPを取得するためにコードを変更する必要があることがよくあります。


ここでは、OCPではなく、単一責任プリンシパルについて話していると思います。
サイードネアマティ

1
SRPなしでOCPを現実的に使用することはできないと言っています。やりすぎるコードは拡張できず、再利用できません。SOLIDはほとんど重要度の高い順に書かれており、各原則は実行可能になる前の原則に依存しています。
CodexArcanum

この答えはもっと支持されるべきです。
アシッシュグプタ

0

古いコードを変更するのではなく、新しいコードを作成してプログラムの動作を変更する場合は、オープンクローズの原則に従います。

すべての可能な変更に対してオープンなコードを書くことは非常に不可能であるため(そして分析麻痺を入力するためにしたくない)、修正ではなく拡張によって現在取り組んでいるすべての異なる動作に応答するコードを記述します。

新しい動作を許可するために何かを変更するだけでなく、変更する必要があるものに遭遇した場合、変更点を把握し、新しいコードを記述してその動作を変更できるように、動作を変更せずにプログラムを再構築します。

したがって、これがあなたのケースにどのように適用されるか:

クラスに新しい関数を追加する場合、クラスはオープン/クローズされませんが、オーバーロードしている関数のクライアントはオープン/クローズされます。

クラスで機能する新しい関数を単純に追加する場合は、クラスと関数のクライアントの両方がオープン/クローズされます。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.