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>