記事を書いた背景
オブジェクト指向(OOP)は、実際のコード例を見ると、その利点が分かりやすくなるのではないかと思い、記事にしてみました。
コード例(非オブジェクト指向)
今回はPythonで、簡単な銀行口座の機能を作ってみます。
機能は、残高確認、預け入れ、引き出し、です。
まずは、非オブジェクト指向から
account_number_A=1234
password_A=12340000
zandaka_A=account_number_A*password_A
account_number_B=2345
password_B=23450000
zandaka_B=account_number_B*password_B
#すべてのアカウントの、ナンバー、パスワード、残高が入っている辞書のリスト
private_list=[{'account_number':account_number_A,'password':password_A,'zandaka':zandaka_A},{'account_number':account_number_B,'password':password_B,'zandaka':zandaka_B}]
def account_is_current(account_number, password):
#private_listから、account_numberとpasswordが一致している要素があればTrueを返す
for account in private_list:
if account['account_number'] == account_number and account['password'] == password:
return True
return False
def bank_zandaka(account_number,password):
for item in private_list:
if item['account_number'] == account_number :
print('あなたの預金残高は、'+str(item['zandaka'])+'円です')
return True
return False
def bank_hikidashi(account_number, password, price):
for item in private_list:
if item['account_number'] == account_number and account_is_current(account_number, password):
# 残高が、引き出し額より多いか確認
if item['zandaka'] >= price:
item['zandaka'] -= price
return True
else:
return False
return False
def bank_azukeire(account_number, password, price):
for item in private_list:
if item['account_number'] == account_number and account_is_current(account_number, password):
item['zandaka'] += price
return True
return False
def zandaka_kakunin(account_number, password):
if bank_zandaka(account_number,password):
pass
else:
print("不正なログインです")
def hikidashi(account_number, password, price):
if bank_hikidashi(account_number, password, price):
print("引き出し成功")
else:
print("引き出し失敗:残高不足または不正なログインです")
def azukeire(account_number, password, price):
if bank_azukeire(account_number, password, price):
print("預け入れ成功")
else:
print("預け入れ失敗:不正なログインです")
実際にこの機能を使う、runtime.py
はこちら
# 非オブジェクト指向
from non_oop import *
azukeire(1234,12340000,100)##預け入れ成功
hikidashi(1234,12340000,100)##引き出し成功
azukeire(2345,23450000,1000)##預け入れ成功
hikidashi(2345,23450000,2000)##引き出し成功
hikidashi(123,12300,200)##引き出し失敗:残高不足または不正なログインです
zandaka_kakunin(1234,12340000)##あなたの口座残高は、15227560000円です
zandaka_kakunin(2345,23450000)##あなたの口座残高は、54990249000円です
runtime.py
の中で、azukeire()、hikidashi()、いずれの関数を使うにせよ、いちいちナンバーとパスワードを引数に入れなければならず、不便です。
non_oop.py
についても、コードの初めの方に、それぞれのアカウントのナンバー、パスワード、残高をすべて定義しているため、コードが無駄に長く、読みにくくなっています。また、関数が同じようにいくつも配置されているため、それぞれの関数の役割が、分かりにくくなっています。
コード例(オブジェクト指向)
先ほどの例での問題点を改善すべく、クラスを用いて以下のように記述することができます。
class Bank:
#インスタンス生成時に実行される
def __init__(self,*account_numbers) -> None:
self.private_list=[]
# アカウント情報の複数作成
for account_number in account_numbers:
password_i=int(str(account_number)+'0000')
zandaka_i=account_number*password_i
dict_i={'account_number':account_number,'password':password_i,'zandaka':zandaka_i}
#private_listにアカウントごとの辞書型データを追加
self.private_list.append(dict_i)
def account_is_current(self,account_number, password):
for account in self.private_list:
if account['account_number'] == account_number and account['password'] == password:
return True
return False
def bank_zandaka(self,account_number,password):
for item in self.private_list:
if item['account_number'] == account_number :
print('あなたの預金残高は、'+str(item['zandaka'])+'円です')
return True
return False
def bank_hikidashi(self,account_number, password, price):
for item in self.private_list:
if item['account_number'] == account_number :
# 残高が、引き出し額より多いか確認
if item['zandaka'] >= price:
item['zandaka'] -= price
return True
else:
return False
return False
def bank_azukeire(self,account_number, password, price):
for item in self.private_list:
if item['account_number'] == account_number :
item['zandaka'] += price
return True
return False
#2つのアカウント情報を作成したbank_insを作る(インスタンス生成)
bank_ins=Bank(1234,2345)
class Account:
#インスタンス生成時に実行される
def __init__(self,account_number,password) :
#アカウントが存在しているか確認する
if bank_ins.account_is_current(account_number,password):
#アカウント情報定義
self.account_number=account_number
self.password=password
print('アカウントは正常に作成されました')
#存在していなければ、処理を中止
else:
print("不正なログインです")
#処理を中止
exit()
def zandaka_kakunin(self):
if bank_ins.bank_zandaka(self.account_number,self.password):
pass
else:
print("失敗しました")
def hikidashi(self,price):
if bank_ins.bank_hikidashi(self.account_number,self.password, price):
print("引き出し成功")
else:
print("引き出しに失敗しました。")
def azukeire(self, price):
if bank_ins.bank_azukeire(self.account_number,self.password, price):
print("預け入れ成功")
else:
print("預け入れに失敗しました")
そして、runtime.py
がこちら
# オブジェクト指向
from oop import *
account_A=Account(1234,12340000)##アカウントは正常に作成されました
account_B=Account(2345,23450000)##アカウントは正常に作成されました
account_A.azukeire(100)##預け入れ成功
account_A.hikidashi(100)##引き出し成功
account_B.azukeire(1000)##預け入れ成功
account_B.hikidashi(2000)##引き出し成功
account_A.zandaka_kakunin()##あなたの口座残高は、15227560000円です
account_B.zandaka_kakunin()##あなたの口座残高は、54990249000円です
account_C=Account(123,12300)##不正なログインです
runtime.py
では、いちいちアカウント情報を引数に入れる必要がなくなり、より直感的な記述ができるようになっています。また、アカウントのインスタンス生成時に、アカウントが存在しているかどうかを確認できる、という利点が生まれています。
oop.py
では、関連するメソッド(関数)を同じクラス内に記述することで、それぞれの関数の役割が、より分かりやすくなっています。
Bankクラス内で、アカウント情報の作成をしているため、non_oop.py
では最初に記述されていた情報が、すべてBankクラス内で収まることになり、コードが読みやすくなりました。アカウント情報を変えたいときは、bank_ins=Bank(1234,2345,123)などのように、一行変更するだけで良くなったことも、大きな利点です。
コード例を通して
oop.py
は、一貫して、関連する変数、メソッドを、同じクラス内に記述する、といったことがなされています。
最後に
オブジェクト指向という概念は、まだまだ奥が深く、本来は、解説すべきことがまだまだ数多くあるようです。
私もオブジェクト指向を完全に理解できているとは言えず、このようなざっくりとした解説になってしまいましたが、少しでも利点が伝わる記事になっていれば幸いです。