Pythonに固有ではないオブジェクト指向のデザインについて質問がありますが、私のコードはPythonであるため、そのようにタグ付けしました。どのクラスを実装する責任があるかをどのように決定するのですか?複数のクラスに影響を与える可能性のある特定の機能?いくつかの優れたガイドライン(もしあれば)または考慮事項は何ですか?
以下のTownクラスの例では、町への移動、または町からの移動の動作はTownクラスとInhabitantクラスに分かれています。コードは機能します。しかし、この動作を1つのクラスだけに割り当てる説得力のある理由があるかどうか疑問に思っています。 TownメソッドaddpeopleがInhabitant属性townを更新することを許可するので、各居住者の居住地を追跡できます。
ちょうど良い習慣やスマートオブジェクト指向のデザインを理解しようとしています。
class Town():
def __init__(self,name):
self.name = name
self.inhab = []
def addpeople(self,person):
self.inhab.append(person)
def removepeople(self, person):
self.inhab.remove(person)
class Inhabitant():
def __init__(self,name):
self.name = name
self.town = ""
def move(self,town):
if self.town:
print self.name,"is moving from",self.town.name, "to",town.name
self.town.removepeople(self)
else:
print self.name,"is moving to",town.name
self.town = town
town.addpeople(self)
以下のTownクラスの例では、町への移動または町からの移動の動作は、TownクラスとInhabitantクラスに分けられています。コードは機能します。しかし、この動作を1つのクラスのみに割り当てる説得力のある理由があるかどうか疑問に思っています。 Townメソッド
addpeople
が住民属性タウンを更新できるようにして、各住民の居住地を追跡できるようにします。
この振る舞いを1つのクラスだけに割り当てず、それを現在のクラスと同様に保つことには、実際には十分な理由があります。オブジェクト指向プログラミングでは、各オブジェクトに独自のデータの制御を維持させたいと考えています。変数が属するオブジェクトの外部で変数を変更すると、コードが非常に複雑になり、デバッグが困難になる可能性があります。これは、オブジェクト指向プログラミングの中心となるカプセル化の概念の一部です。
ここで関連するOOPのもう1つの部分は抽象化です。つまり、コード内のオブジェクト間の相互作用をより高いレベルで理解できるようにします。このサンプルコードを見るだけで[〜#〜] i [〜#〜]は、町の住民が町よりもプログラムの焦点であると推測しますユーザーが町ともっと対話している場合、[〜#〜] i [〜#〜]が期待しますより多くの仕事をしている町(Town.addpeople
を呼び出すInhabitant.move
、 例えば)。
したがって、プログラムを作成するときは、どのエンティティが作業を行うエンティティになるかを考えてください。コードがyourと一致すると、何が起こっているかを直感的に抽象化すると、何が何であるかを追跡しやすくなります続行して、コードにバグを導入しないでください。
このプロジェクトの目的に応じて、他に1つアドバイスがあります。これが実際に使用、保守、およびアップグレードするプログラムである場合は、まず使い捨てプロトタイプを記述してくださいです。 Joel Cornettがコメントで述べたように、「それはユースケースに依存します」、つまり、あなたが持っているコードを書くための最良の方法を知るために状況を理解する。これの一部は経験に由来しますが、ほぼ同じプログラムを何度も繰り返し作成しない限り、完全に馴染みのない状況に遭遇します。プロトタイプを書くことは、直面している特定の問題について経験を積むための優れた方法です。なぜなら、プログラムを書くのにかなり遠くまで、何らかの方法でうまくいく理由を理解できないことがよくあるからです。
人々が優れたシステムを作成することを妨げている1つのことは、彼らが彼らのコードに取り付かれるということです。したがって、プロトタイプを作成することを選択した場合は、それが使い捨てであることを認識してください。問題の良い感触を得るためだけに迅速に作成するものです。それはあなたがそれを書いている間に、それがうまくいく必要がないことを理解するのに役立つ限り、それがうまくいく必要さえないことを理解した場合にも役立ちます。プロトタイプを作成すると、コードをどのように作成する必要があるかについて、はるかによく理解できます。そうすれば、最初からやり直して、正しく書き込めます。
つまり、「ユースケースによって異なります」ので、ユースケースを理解し、コードがあなたの理解と一致するようにしてください。
Q。複数のクラスに影響を与える可能性がある特定の機能の実装を担当するクラスを決定するにはどうすればよいですか?良いガイドライン(ある場合)または考慮事項は何ですか?
A。General Responsibility Assignment Software Patterns(or Principles) (略称GRASP)は、クラスに責任を割り当てるためのガイドラインと、オブジェクト指向設計のオブジェクト。
これらのガイドラインは、クラスメソッドを作成する場合のトレードオフと利点を、複数のクラスに影響を与える動作とバランスさせるのに役立ちます。一般に、メソッドを実装する方法について最も知識のあるクラス、他のクラスのコントローラーとして機能するクラス、およびが相互依存の数を最小限に抑える方法でメソッドを配置しようとしています各クラス。
どちらにも問題はありません。これは、ケースごとに異なる答えがある質問です-自分にとってより自然に思われることをしてください。
場合によっては、いずれかの方法を使用する必要があります。他の場合では、両方の方法を並行して使用することもできますが、そうする場合は注意が必要です。
両方の結果がまったく同じであることを確認してください。
サンプルで潜在的なバグをすでに特定しました:addpeople
のTown
は、住民のtown
を更新しません。 Inhabitant
にtown
がまだない場合、town属性が設定されます。 Inhabitant.move
を使用して人物を移動することを選択した場合は、町が設定されます。これはバグを導入する典型的な方法なので、この方法を選択する場合は注意してください。