SOLID
単一責任の法則
同じ役割を入れるということ
[ ]:
class Userinfo(object):
def __init__(self, name, age, phone_number):
self.name = name
self.age = age
self.phone_number = phone_number
def __str__(self):
return "{}{}{}".format(
self.name, self.age, self.phone_number
)
# クラスを分ける
class FikeManager(object):
@staticmethod
def write_to_file(obj, filename):
with open(filename, mode="w") as f:
f.write(str(obj))
userinfo = Userinfo("Taro", 31, "000-000-000")
print(str(userinfo))
FikeManager.write_to_file(userinfo, "tmp.txt")
リスコフの置換原則
継承とか実行できるものは継承先を実行できるようにする。
[2]:
class Rectangle(object):
def __init__(self, width, height):
self._width = width
self._height = height
@property
def width(self):
return self._width
@width.setter
def width(self, width): self._width = width
@property
def height(self):
return self._height
@height.setter
def height(self, height): self._height = height
def calc_area(self):
return self._width * self._height
class Square(Rectangle):
def __init__(self, size): self._width = self._height = size
@Rectangle.width.setter
def width(self, size): self._width = self._height = size
@Rectangle.height.setter
def height(self, size): self._height = self._width = size
def print_area(obj):
change_to_width = 10
change_to_height = 20
obj.width = change_to_width
obj.height = change_to_height
if isinstance(obj, Square):
change_to_height = change_to_height
print("予想={},実際={}".format(
change_to_height * change_to_width,
obj.calc_area()
))
rc = Rectangle(2, 3)
print_area(rc)
sq = Square(5)
print_area(sq)
予想=200,実際=200
予想=200,実際=400
開放閉鎖の原則
ソースコードを変更するのではなく、追加して修正していく
[9]:
from abc import ABCMeta, abstractmethod
# ソースコードを変更するのではなく追加して修正していく
class UserInfo:
def __init__(self, user_name, job_name, nationality):
self.user_name = user_name
self.job_name = job_name
self.nationality = nationality
def __str__(self):
return '{}{}{}'.format(
self.user_name, self.job_name, self.nationality
)
# 抽象クラス
"""必ず継承先を使わないといけない"""
class Comparetion(metaclass=ABCMeta):
@abstractmethod
def is_equal(self, other):
pass
def __and__(self, other):
return AndComparation(self, other)
def __or__(self, other):
return OrComparation(self, other)
class AndComparation(Comparetion):
def __init__(self, *args):
self.comparetions = args
def is_equal(self, other):
return all(
map(
lambda comparation: comparation.is_equal(other),
self.comparetions
)
)
class OrComparation(Comparetion):
def __init__(self, *args):
self.comparetions = args
def is_equal(self, other):
return any(
map(
lambda comparation: comparation.is_equal(other),
self.comparetions
)
)
class Filter(metaclass=ABCMeta):
@abstractmethod
def filter(self, comparetion, item):
pass
class JobNameComparetion(Comparetion):
def __init__(self, job_name):
self.job_name = job_name
def is_equal(self, other):
return self.job_name == other.job_name
class NationalityComparation(Comparetion):
def __init__(self, nationality):
self.nationality = nationality
def is_equal(self, other):
return self.nationality == other.nationality
class UserInfoFilter(Filter):
def filter(self, comparetion, items):
for item in items:
if comparetion.is_equal(item):
yield item
taro = UserInfo('taro', 'salary man', 'Japan')
jiro = UserInfo('jiro', 'police man', 'japan')
john = UserInfo('john', 'salary man', 'USA')
user_list = [taro, jiro, john]
salary_man_comparetion = JobNameComparetion('salary man')
user_info_filter = UserInfoFilter()
for user in user_info_filter.filter(salary_man_comparetion, user_list):
print(user)
japan_comparetion = NationalityComparation('Japan')
for user in user_info_filter.filter(japan_comparetion, user_list):
print(user)
# これをすると__and__が出てくる
salary_man_japan = salary_man_comparetion & japan_comparetion
for user in user_info_filter.filter(salary_man_japan, user_list):
print(user)
tarosalary manJapan
johnsalary manUSA
tarosalary manJapan
tarosalary manJapan
インターフェース分離の法則
いらないコードを書かないようにする。
[3]:
from abc import ABCMeta, abstractmethod
class Athlete(metaclass=ABCMeta):
pass
# ここで分ける
class SwimAthlete(Athlete):
@abstractmethod
def swim(self):
pass
class JumpAthlete(Athlete):
@abstractmethod
def high_jump(self):
pass
@abstractmethod
def long_jump(self):
pass
class Athlete1(SwimAthlete):
def swim(self):
print("I swim")
class Athlete2(SwimAthlete, JumpAthlete):
def swim(self):
print("I swim")
def high_jump(self):
print("I high jump")
def long_jump(self):
print("I long jump")
john = Athlete1()
john.swim()
yuji = Athlete2()
yuji.high_jump()
I swim
I high jump
依存性逆転の原則
ソフトウェア間のモジュール間の依存関係を切り離す方法
[7]:
from abc import ABCMeta, abstractmethod, abstractproperty
#interface(I)は具体的な処理の形は書かない。
class IBook(metaclass=ABCMeta):
# 抽象先でgetterを所持しないといけない。
@abstractproperty
def content(self):
pass
class Book(IBook):
def __init__(self, content):
self._content = content
@property
def content(self):
return self._content
class EBook(IBook):
def __init__(self, content):
self._content = content
@property
def content(self):
return "E" + self._content
class IFormatter(metaclass=ABCMeta):
@abstractmethod
def format(self, i_book: IBook):
pass
class HtmlFormatter(IFormatter):
def format(self, i_book: IBook):
return "<h1>" + i_book.content + "</h1>"
class XmlFormatter(IFormatter):
def format(self, i_book: IBook):
return "<xml>" + i_book.content + "</xml>"
class Printer:
# 継承前がabstructだから、排除する
def __init__(self, i_formatter: IFormatter):
self._i_formatter = i_formatter
def print(self, i_book: IBook):
formatted_book = self._i_formatter.format(i_book)
print(formatted_book)
book = Book("My book")
html_formatter = HtmlFormatter()
html_printer = Printer(html_formatter)
html_printer.print(book)
xml_formatter = XmlFormatter()
xml_printer = Printer(xml_formatter)
xml_printer.print(book)
ebook = EBook("My Ebook")
xml_printer.print(ebook)
<h1>My book</h1>
<xml>My book</xml>
<xml>EMy Ebook</xml>