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

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

新規登録して質問してみよう
ただいま回答率
85.48%
Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト指向

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

Q&A

解決済

2回答

464閲覧

オブジェクト指向プログラミングにおけるプログラム構造(クラス)設計

finok

総合スコア1

Python 3.x

Python 3はPythonプログラミング言語の最新バージョンであり、2008年12月3日にリリースされました。

オブジェクト指向

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

0グッド

0クリップ

投稿2022/02/18 15:34

似たような処理をするindividualClassAとindividualClassBをコーディングしたいと考えています。
今後もクラスを追加していきたいので、できるだけクラス間の結合度を弱めつつ重複を排除するためにオブジェクト指向について説明した書籍を読みつつコーディングしました。(実用と勉強半々です。)

以下のコード群ような構成にしてみましたが、下のような問題があると思います。

  • var1、var2のようなindividualClass内で共通的に使用するパラメータが増えると、パラメータを使用するメソッド(individualMethod)の引数が長くなる。(2つだとあまり実感がないが、5つ以上になると汚くみえる)
  • 引数とすることを避けるために、各メソッドからパラメータを直接参照できるようグローバル変数にすると、integrityを保証できない(予期せず変更されてしまう可能性がある)

こうした問題を解消するようなうまいプログラム構造設計の方法はあるのでしょうか。
そもそも以下のようなコーディングはオブジェクト指向プログラミングとして適切かつ効率的ないのでしょうか。(何かツッコミどころがないでしょうか)

やや漠然とした質問ですみません。
なお、individualClassは2つだけではなく、さらに増やしていくつもりでいます。individualClassの固有パラメータも2つだけではなく増やすつもりです。

python

1class sharedClass: 2 3 def sharedMethodA(): #実装は省略 4 5 def sharedMethodB(): #実装は省略 6 7 def sharedMethodC(): #実装は省略

python

1class individualSuperClass: #実装は省略

python

1class individualClassA(individualSuperClass): 2 3 def __init__(self): 4 # ClassA 固有のパラメータ 5 self.__var1 = '' 6 self.__var2 = '' 7 8 def individualMethod(self): 9 # ClassA 固有の処理を実行 10 hogehoge 11 # ClassA 固有の処理を実行後、ClassAのパラメータを使って共通処理を行う 12 sc = sharedClass() 13 sc.sharedMethodA(self.__var1, self.__var2) 14 sc.sharedMethodB(self.__var1) 15 sc.sharedMethodC(self.__var2)

python

1class individualClassB(individualSuperClass): 2 3 def __init__(self): 4 # ClassB 固有のパラメータ 5 self.__var1 = '' 6 self.__var2 = '' 7 8 def individualMethod(self): 9 # ClassB 固有の処理を実行 10 hogehoge 11 # ClassB 固有の処理を実行後、ClassBのパラメータを使って共通処理を行う 12 sc = sharedClass() 13 sc.sharedMethodA(self.__var1, self.__var2) 14 sc.sharedMethodB(self.__var1) 15 sc.sharedMethodC(self.__var2)

python

1def main(): 2 ic = individualClassA() 3 ic.individualMethod() 4 ic = individualClassB() 5 ic.individualMethod() 6 7if __name__ == "__main__": 8 main()

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

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

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

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

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

yuki23

2022/02/19 07:11

individualClassX とは何をするクラスで、sharedClass とは何をするクラスなのかという具体的な情報がないと、具体的なアドバイスをすることは難しいと思います
finok

2022/02/19 12:51

用途によってクラスの構成が変わるということでしょうか。 sharedClassはindividualClassで共通的に行う処理を独立させたものです。 individualClassは軽自動車やトラックのクラスで、sharedClass(のメソッド)はタイヤをつけるとかエンジンを搭載するとか、そういうイメージだとお伝えすれば大丈夫でしょうか。 つけるタイヤやエンジンを変えつつ軽自動車やトラックを生成するということです。
yuki23

2022/02/20 04:57

それは sharedClass, IndividualClass の具体的な説明ではなく、「プログラミング言語におけるクラスという機能は何か」の説明ですよね? 重要なのは、そのような機能を使って、 sharedClass, IndividualClass がプログラムの中でどのようなことを実現したいのか、表現したいのかということです。 finok さんの作っているプログラムは、軽自動車やトラックやタイヤやエンジンを扱うプログラムなんでしょうか?
guest

回答2

0

ベストアンサー

var1、var2のようなindividualClass内で共通的に使用するパラメータが増えると、パラメータを使用するメソッド(individualMethod)の引数が長くなる。(2つだとあまり実感がないが、5つ以上になると汚くみえる)

単純に method( a, b, c, d ... ) とやるのはアレだからってことですか?
それなら私なら「クラスとして抽出する」ですかね。抽出っていうか、method( a, b, c ... ) でいう a~z のような引数を ArgumentEx とかみたいなクラスとして定義し、それを渡す。

質問にあるコードであれば、individualMethodメソッドの処理部を見ると処理内容がほぼ一致している。

その場合も、やはり引数を別のクラスとして切り出すかな。

たとえば、ArgumentExとしてクラスにし、

def __init__(self, argumentEx): // <- これと # ClassB 固有のパラメータ argumentEx_ = argumentEx // <- これと def individualMethod(self): # ClassB 固有の処理を実行 hogehoge # ClassB 固有の処理を実行後、ClassBのパラメータを使って共通処理を行う argumentEx.commonMethod() # <- これ!

のように。

引数とすることを避けるために、各メソッドからパラメータを直接参照できるようグローバル変数にすると、integrityを保証できない(予期せず変更されてしまう可能性がある)

これも上記のオブジェクトにすればいいはず。


[追記1]

この場合、新しいindividualClassを追加しようとすると、パラメータクラスも同時に追加することとなり、2つクラスを作らなければいけないのが少々気になっていました

A,Bが持つフィールドってまったく別物ですか? たとえば Aでは "攻撃力"と"守備力", Bでは "回復力"と"ダメージ力"とかみたいに。
まったく別物であればクラスごとに作ることになりますが、私の最初の所見では、A,Bともにほぼ同じフィールド(個別のものがいくつかあるぐらい)だと考えていたのですが。

ほぼ同じフィールドであればまとめるためのクラスは一個でいいです。

...commonMethodをそれらの中に定義することとなると、これは共通処理なので、クラス間で重複コードが生じることとならないでしょうか。

まあ、でしょうね。ただ、上で述べたように私の解釈ではA,Bは同じフィールドを持っているっていうことなので。(もちろん中身自体は別物だけど)

インターフェースみたいなものを用意してこれを実装して引数をまとめたやつを定義する。

単純に 上でいう ArgumentExは commonInitメソッドみたいな共通の初期化をするようなメソッドを持ち、そのメソッドをA,Bがそれぞれ動かす。

def __init__(self, argumentEx): // <- これと # ClassB 固有のパラメータ argumentEx_ = argumentEx // <- これと

に関しては、単純に argumentExっていう引数としてのオブジェクトを受け取って フィールドとしての argumentEx_ にセットしているだけです。
別にget/set系でやってもいいですが。

単純に「クラスにまとめればいいじゃね?」ってことが言いたかっただけです。

投稿2022/02/19 09:02

編集2022/02/20 13:56
BeatStar

総合スコア4958

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

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

finok

2022/02/19 12:33

ありがとうございます。クラスとしてまとめるのも手ですよね。 この場合、新しいindividualClassを追加しようとすると、パラメータクラスも同時に追加することとなり、2つクラスを作らなければいけないのが少々気になっていました。各パラメータクラス各individualClassと1対1対応になるなら、individualClass内に書いてしまうのが自然であり、実装上の都合でクラスを分割することに少し違和感があったということです。 ただ、それを割り切ればイメージしていたものとだいぶ近いものです。 ちなみに、ArgumentExクラスってindividualClassA、individualClassBごとに定義する必要があると思いますので、ArgumentExAとかArgumentExBとして定義することとなると思いますが、commonMethodをそれらの中に定義することとなると、これは共通処理なので、クラス間で重複コードが生じることとならないでしょうか。 それとも、そうではなくてArgumentExを共有のパラメータクラスとして1つだけとすることとし、individualClass内のコンストラクタでsetter経由でパラメータの値を設定するということでしょうか。 argumentEx_ = argumentEx の部分が勉強不足でよく理解できませんでした。
finok

2022/02/20 23:39

追記のご説明、ありがとうございました。 パラメータクラスを1つ作る方法で実装してみたいと思います。
guest

0

共通で利用したい変数をindividualSuperClassにprivateで持たせて、取得はgetterのみという形にするというのはどうでしょう。

python

1class parent: 2 def __init__(self): 3 self.__ver1 = 1 4 self.__ver2 = 2 5 def ver1(self): return self.__ver1 6 def ver2(self): return self.__ver2 7 8class child(parent): 9 def myprint(self): 10 print(self.ver1()) 11 print(self.ver2()) 12 13a = child() 14a.myprint()

これであればパラメータが増えてきたなく見えるのを避け、かつ外部からの変更を防ぐことができます。

投稿2022/02/18 20:09

退会済みユーザー

退会済みユーザー

総合スコア0

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

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

finok

2022/02/19 03:29

ありがとうございます。 privateにした上でgetterで値を取得するなら、意図せず値が変更されてしまうことを防ぎつついろんな場所から参照できますね。 今回はindividualClassAとindividualClassBで異なるパラメータを持たせたいのですが、その場合はsharedClassの各メソッドの実行前にsetterで値を設定しておくこととなるのでしょうか。 また、パラメータはどちらかというとsharedClassのメソッド内で利用したいのですが、sharedClassからindividualSuperClassの変数をgetterで取得することはできるのでしょうか。 私もいろいろ構成考えてみましたが、あちらを立てるとこちらが立たずな状況で行き詰ってしまいました。
退会済みユーザー

退会済みユーザー

2022/02/19 03:42

getter自体はpublicなので特に問題なく参照可能です。 ClassAとClassBで異なるパラメータを持たせたいという部分はコンストラクタで実現させるのがよいかと思います。 (setterを用意したらprivateで隠ぺいした意味がなくなりそうです)
finok

2022/02/19 12:12

sharedClassは独立したクラスなので、例えばindividualClassAから呼び出された場合、var1を参照するにはindividualClassA().var1と書かないといけないと思います。 すると、individualClassBから呼び出された場合もindividualClassAのパラメータを参照することとなってしまわないでしょうか。if文で参照するクラスを分岐させるのはオブジェクト指向ではないと思いますし・・・。 個別に引数指定するか、パラメータを含むオブジェクトを引数にするか、BeatStarさんの言うように共有のパラメータクラスを用意しないといけないのでしょうね。
退会済みユーザー

退会済みユーザー

2022/02/19 15:11

> individualClassAから呼び出された場合、var1を参照 individualClassA内のメソッドでsharedClassのメソッドにvar1を渡す場合はself.var1()という形でgetter経由になるかと思いますが、あくまでもreadonlyなのでかまわないのではないでしょうか。 > individualClassBから呼び出された場合もindividualClassAのパラメータを参照する すみません、これはちょっと意味が分かりませんでした。 クラスが異なっているので関係ないかと思いますが…
guest

あなたの回答

tips

太字

斜体

打ち消し線

見出し

引用テキストの挿入

コードの挿入

リンクの挿入

リストの挿入

番号リストの挿入

表の挿入

水平線の挿入

プレビュー

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

ただいまの回答率
85.48%

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

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

質問する

関連した質問