nonoのポートフォリオサイト

SOLIDの原則

SOLIDの原則2 開放閉鎖の原則

クラス、モジュール、関数などのソフトウェアのぶひんは拡張に対しては開いており、修正に対しては閉じていなければならないとする原則です。


サンプルコード


# 開放閉鎖の原則1
# open_closed.py

# 開放閉鎖の原則を守った記述するには、、
from abc import ABCMeta, abstractmethod


class UserInfo(object):
    """ユーザ情報の保持"""
    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 Comparation(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(Comparation):

    def __init__(self, *args):
        # 可変長の引数をとる
        self.comparations = args

    def is_equal(self, other):
        return all(
            map(
                lambda comparation: comparation.is_equal(other),
                self.comparations
            )
        )


class OrComparation(Comparation):

    def __init__(self, *args):
        # 可変長の引数をとる
        self.comparations = args

    def is_equal(self, other):
        return any(
            map(
                lambda comparation: comparation.is_equal(other),
                self.comparations
            )
        )

class Filter(metaclass=ABCMeta):

    @abstractmethod
    def filter(self, comparation, item):
        pass


class JobNameComparation(Comparation):

    def __init__(self, job_name):
        self.job_name = job_name

    def is_equal(self, other):
        return self.job_name == other.job_name


class NationalityComparation(Comparation):

    def __init__(self, nationality):
        self.nationality = nationality

    def is_equal(self, other):
        return self.nationality == other.nationality


class UserInfoFilter(Filter):
    def filter(self, comparation, items):
        for item in items:
            if comparation.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_comparation = JobNameComparation('salary man')
user_info_filter = UserInfoFilter()
print(' --- job name --- ')
for user in user_info_filter.filter(salary_man_comparation, user_list):
    print(user)

print(' --- nationarity --- ')
japan_comparation = NationalityComparation('Japan')
for user in user_info_filter.filter(japan_comparation, user_list):
    print(user)

#AndComparationを使ってみる。 & をつかつ
print('-'*10)
salary_man_and_japan = salary_man_comparation & japan_comparation
for user in user_info_filter.filter(salary_man_and_japan, user_list):
    print(user)

#OrComparationを使ってみる。| (パイプ)でつなぐ
print('-'*10)
salary_man_or_japan = salary_man_comparation | japan_comparation
for user in user_info_filter.filter(salary_man_or_japan, user_list):
    print(user)

# for man in UserInfoFilter.filter_users_job(user_list, 'police man'):
#     print(man)
#
# for man in UserInfoFilter.filter_users_nationality(user_list, 'Japan'):
#     print(man)