質問をすることでしか得られない、回答やアドバイスがある。

15分調べてもわからないことは、質問しよう!

新規登録して質問してみよう
ただいま回答率
85.48%
オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

Q&A

解決済

3回答

4974閲覧

Python オブジェクト指向 クラス設計について

_Victorique__

総合スコア1392

オブジェクト指向

オブジェクト指向プログラミング(Object-oriented programming;OOP)は「オブジェクト」を使用するプログラミングの概念です。オブジェクト指向プログラムは、カプセル化(情報隠蔽)とポリモーフィズム(多態性)で構成されています。

Python

Pythonは、コードの読みやすさが特徴的なプログラミング言語の1つです。 強い型付け、動的型付けに対応しており、後方互換性がないバージョン2系とバージョン3系が使用されています。 商用製品の開発にも無料で使用でき、OSだけでなく仮想環境にも対応。Unicodeによる文字列操作をサポートしているため、日本語処理も標準で可能です。

0グッド

5クリップ

投稿2017/06/16 07:42

編集2017/06/16 07:58

###前提・実現したいこと
ここ最近オブジェクト指向関連の稚拙な質問ばかりで申し訳ないです。
クラス設計についてどうすればいいのか分からないので教えて欲しいです。

##該当のソースコード
#####Report.py

python

1from Dict import Dictonary 2 3class Report: 4 def __init__(self,name,comment): 5 self._name = Name(name) 6 self._comment = Comment(comment) 7 8 def macthWords(self): 9 dict = Dictionary() 10 words = self._comment.parse() 11 return [word for word in words if dict.isMatch(word)] 12 13 14class Name: 15 def __init__(self,name): 16 self._name = name 17 18 def isSame(self,name): 19 return self._name == name 20 21class Comment: 22 def __init__(self,comment): 23 self._comment = comment 24 25 def parse(self): 26 #parse処理 27 return words

#####Dict.py

python

1class Dictionary: 2 def __init__(self): 3 self._dict = self.__loadDictionary() 4 5 def __loadDictionary(self): 6 #ファイルを読み込んで辞書を作成 7 return dict 8 9 def isMatch(self,word): 10 return word in self._dict

##この設計の問題点
今現状のクラス図はこのような感じでしょうか
NameとCommentはラップクラスです。

python

1 | 2 | 3 | 4[class Report:] ------------------------[class Dictionary:] 5 | 6 |--------------------7 | | 8[class Name:] [class Comment:]

問題が2つあります。
①ReportクラスのmatchWordsメソッドが呼ばれるたびに辞書を作成しまう。
②単一責任の原則に反しているのではないか?(commentでparseしたものをReportクラスで扱っている為)

②に関してはラップクラスとしてのCommentの責任からは離れているので問題ないのかなとは思っているのですが分からないので教えてください。
①は何か解決策がありましたら教えてください。

これ以外にも何かおかしかったり、こうした方がいいというのがあれば教えてください。

気になる質問をクリップする

クリップした質問は、後からいつでもMYページで確認できます。

またクリップした質問に回答があった際、通知やメールを受け取ることができます。

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

guest

回答3

0

ベストアンサー

(1) ReportクラスのmatchWordsメソッドが呼ばれるたびに辞書を作成しまう。

これはオブジェクト指向としての話題か実装テクニックの話かよくわかりませんが・・・後者だとしてコメントしてみます。

この辞書をみると「何物にも依存しない辞書」に見えるので、インスタンスのライフサイクルをどうするか考えてみてはいかがでしょうか?辞書インスタンスのライフサイクルはメソッドの呼び出し期間、インスタンスの存在期間、クラスの存在期間、アプリケーションの存在期間のいずれにするかで設計に違いがでると思います。

またあまりよいことではないかも知れませんが、Dictionaryのインスタンスをいくつ作っても辞書本体の情報はDictionaryクラスが静的に保持しているという作り方もできなくはありません。利用者は毎回インスタンスを作るのですが、実際のロードはDictionaryクラスが「必要に応じて1回だけ」にするといったトリックです。

(2) 単一責任の原則

CommentやReportが「何であって何でないか」の設計次第だと思います。例えば「コメント」というクラス名からは「単語を分解する」とか「キーワードとそれ以外を取り出す」といった機能のイメージが(自分は)わいてきません。またReportが「何をリポートする目的のものか」いいかえれば「現実世界のどういった問題をモデル化したものか」イメージがわかないので「何をどのクラスに役割分担させようとしているか」がわかりません。それがイメージしにくいと各クラスが何を意味しているかがわからないのではっきりとした意見が持てない気がします。

投稿2017/06/16 09:24

KSwordOfHaste

総合スコア18394

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_Victorique__

2017/06/16 09:49

(2)に関しては確かにそうですね。 Reportに関しては、アンケートをイメージしてもらえると良いかもです。名前とコメントを書いてもらったものが複数人分あります。ですので、Commentクラスに関してはcommentを保持・操作する(commentを書き換えることはない)で、Reportクラスに関してはNameとCommentを用いた処理をします。 でもどうしてもcommentがメインになってしまっているのが現状です。
KSwordOfHaste

2017/06/16 09:57

なるほど、アンケートに特定の単語が含まれているかどうかを調べるといったモデルなんですね。 だとするとCommentクラスではなくアンケートクラスとして興味のある単語の抜き出し機能を持っている設計もよい気がします。つまりReportクラスは不要という感じで。
_Victorique__

2017/06/16 10:12

そうするとcommentとnameを結び付けられなくなってしまいます。実際はnameの他にもageやsex、dateなどの情報もアンケート1枚に含んでいるのでそれらをまとめる為にReportクラスを作った感じです。どのようにすれば良いでしょうか?
_Victorique__

2017/06/16 10:17

実際には、ageやsex、dateを条件にcommentを操作する感じです。
KSwordOfHaste

2017/06/16 10:19

Reportクラスは「単に関連するひとまとまりの情報を集約」するためだけのクラスとして考えてもいいのではないですか?情報がまとまっていて属性だけがあるDBアプリケーションでよく用いられる「データクラス」のようなものとして考えるわけです。
KSwordOfHaste

2017/06/16 10:26

もし別のReportクラスを設計することを想定するとキーワードを抜き出すのがReportにあっていいのだろうか・・・という気がちょっとします。またキーワードを抜き出すのではなく、単に単語の集合を表現したいだけのクラスを利用したい場合はCommentにキーワードを抜き出す機能が含まれているとジャマに感じ「もっと単純な機能のクラスがほしかった」といいたくなる状況も想像できます。やはり「どう設計するか」にはバリエーションがあると思います。
_Victorique__

2017/06/16 10:30

この日付のReportに対して処理したい時があるのでそれをReportに書く、という風に考えていましたが、ReportのDateにその日付か判定するメソッドを持たせて、それで処理するので十分ですね。これが正しいのならデータクラスとしてありだと思いますがどうですか?
KSwordOfHaste

2017/06/16 10:36

そういう設計も充分アリと思います。
_Victorique__

2017/06/16 10:45

ありがとうございます。 最後に、>pashango2さんの回答コードをみてもらいたいのですが、Commentクラスのクラス変数としてDictionaryクラスのインスタンスを保持するのはOOP的に問題ないのでしょうか?
KSwordOfHaste

2017/06/16 10:59

pashango2さんの考え方は 「辞書はReportに依存する情報」 「インスタンスごとに異なるものではなく共通のもの」 という前提での設計であり、その前提が質問者さんの意図にマッチするかどうかは別として、OOPとして自然な設計の一つだと自分は思います。
_Victorique__

2017/06/16 11:00

ありがとうございます!全て解決しました!
guest

0

①に関して、一番簡単な方法は以下の通りです。

python

1class Report: 2 _dict = Dictionary() 3 4 def __init__(self,name,comment): 5 self._name = Name(name) 6 self._comment = Comment(comment) 7 8 def macthWords(self): 9 words = self._comment.parse() 10 return [word for word in words if self._dict.isMatch(word)]

コードを読む限り、実ファイルからいつも同じ辞書を作成しているようなので、クラスメンバを使います。
C++で言うところのstaticメンバですね。

②に関して言えば、どこでもいいと思います。
というのも、責任の所在を議論するにはCommentクラスの機能が少なすぎます。

その他
設計には個々の好みがあるので、確実にこうした方がいい部分だけ列挙します。

Directoryクラスは実ファイルと密結合しているし、各々のクラス同士が少し結合度が高いかなと思います。
Dependency Injectionなどで少し結合度を下げた方が良いと思います。

Pythonじゃなくて「Javaっぽいな」というのが印象です、少なくともPEP8を守った方がよいかなと思います。dictなどのビルトインクラスの名前の上書きしている部分があるので、flake8などの静的解析ツールを導入したほうがよいですよ。

投稿2017/06/16 09:25

編集2017/06/16 09:30
pashango2

総合スコア930

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

_Victorique__

2017/06/16 09:36

これってスタティッククラスにするってことですか? ちなみにReportのインスタンスを複数作った場合でも初期化は一度だけになります?インスタンスを作るたびに辞書を作ることはありませんか?
pashango2

2017/06/16 09:37

いえ、スタティッククラスにする必要はありません。 普通にインスタンを生成してください、それでも_dictは1回しか初期化はされません。
_Victorique__

2017/06/16 09:40

なるほどです。 すごくスッキリしていますが、これってOOP的に問題はないのですか?
pashango2

2017/06/16 11:49 編集

問題はありますよ、もしかしたらボロカスに言われるかもしれません。 しかし、この方法は「これ以上ないくらいシンプル」という何にも代えがたい力があります。 この方法で将来的に問題が出ないかもしれないのに、先回りしてシンプルさを崩す不可逆な変更をする事は愚策であると思います、不確定な未来に対しての過剰投資であり、早すぎる最適化です。 私なら問題が発覚してから対処します、対処しやすいようにある程度の軸足を考えて組む必要がありますが・・・ まぁ、設計は好みですので、この意見に納得できない場合はDictionaryを外部から注入してください。 Dictionaryの寿命管理責任はReportクラスよりも上のクラスにありますので。
pashango2

2017/06/16 11:50 編集

上のコメントはDirectory -> Dictionaryでした、修正しました。
guest

0

最終的に以下のように使えるようになったらオブジェクト指向だと思います。

python

1dictionary = Dictionary('file') 2report = Report('name', 'comment') 3words = dictionary.matchWords(report.comment.parse())

投稿2017/06/16 09:18

編集2017/06/16 09:20
YouheiSakurai

総合スコア6142

バッドをするには、ログインかつ

こちらの条件を満たす必要があります。

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

15分調べてもわからないことは
teratailで質問しよう!

ただいまの回答率
85.48%

質問をまとめることで
思考を整理して素早く解決

テンプレート機能で
簡単に質問をまとめる

質問する

関連した質問