「クラスを複数の方向に拡張させる」パターンです。
①:配列のソートをクイックソートまたはバブルソートで行います(方向①)
②:後に、①の機能に、ソートの時間を計測する機能を足します(方向②)
クイックソート・バブルソートについてはqiitaの記事よりお借りしたコードを用います。
# バブルソート
def bsort(a):
for i in range(len(a)):
for j in range(len(a)-1, i, -1):
if a[j] < a[j-1]:
a[j], a[j-1] = a[j-1], a[j]
return a
# クイックソート
def qsort(a):
if len(a) in (0, 1):
return a
p = a[-1]
left = [x for x in a[:-1] if x <= p]
right = [x for x in a[:-1] if x > p]
return qsort(left) + [p] + qsort(right)
# 簡易テスト
if __name__ == "__main__":
print(bsort([2, 7, 3, 4, 9, 1]))
print(qsort([2, 7, 3, 4, 9, 1]))
import time
def main():
l = [2, 7, 3, 4, 9, 1]
sorter_quick = Sorter(QuickSorter())
print(sorter_quick.sort(l))
sorter_bubbl = Sorter(BubbleSorter())
print(sorter_bubbl.sort(l))
sorter_quick_timer = TimeSorter(QuickSorter())
print(sorter_quick_timer.timesort(l))
sorter_bubbl_timer = TimeSorter(BubbleSorter())
print(sorter_bubbl_timer.timesort(l))
###############
# バブルソート
def bsort(a):
for i in range(len(a)):
for j in range(len(a)-1, i, -1):
if a[j] < a[j-1]:
a[j], a[j-1] = a[j-1], a[j]
return a
# クイックソート
def qsort(a):
if len(a) in (0, 1):
return a
p = a[-1]
left = [x for x in a[:-1] if x <= p]
right = [x for x in a[:-1] if x > p]
return qsort(left) + [p] + qsort(right)
###############
# ①の機能の実装
class Sorter:
def __init__(self, sorter):
self.sorter = sorter
def sort(self, a):
return self.sorter.sort(a)
class SortImple:
def sort(a):
raise NotImplementedError
class QuickSorter(SortImple):
def __init__(self):
pass
def sort(self, a):
return qsort(a)
class BubbleSorter(SortImple):
def __init__(self):
pass
def sort(self, a):
return bsort(a)
# ②の機能拡張
class TimeSorter(Sorter):
def timesort(self, a):
start = time.time()
a_sorted = self.sorter.sort(a)
print(time.time() - start)
return a_sorted
if __name__ == "__main__":
main()
まずは素直にSorterに対して継承することで実装します。
クラス図は以下のようになります。
import time
# main, qsort, bsortは同じなので省略
# ①の機能の実装
class Sorter:
def __init__(self):
pass
def sort(self, a):
raise NotImplementedError()
class QuickSorter(Sorter):
def __init__(self):
pass
def sort(self, a):
return qsort(a)
class BubbleSorter(Sorter):
def __init__(self):
pass
def sort(self, a):
return bsort(a)
# ②の機能拡張
# QuickSorterはSorterを継承しているため、TimerSorterでsortするには再度継承が必要
# (クラス名も変更の必要がある)
class TimerSorter(Sorter):
def __init__(self):
pass
def timesort(self, a):
start = time.time()
a_sorted = self.sort(a)
print(time.time() - start)
return a_sorted
class TimeQuickSorter(TimerSorter):
def __init__(self):
pass
def sort(self, a):
return qsort(a)
class TimeBubbleSorter(TimerSorter):
def __init__(self):
pass
def sort(self, a):
return bsort(a)
if __name__ == "__main__":
main()
サンプルコードのようにすることで、QuickSorter()
, BubbleSorter()
のコードの重複が解消されます。
一番大事なところはSorterクラスの以下の部分です。
class Sorter:
def __init__(self, sorter):
self.sorter = sorter
def sort(self, a):
return self.sorter.sort(a)
アンチパターンでは、Sorter
クラスのsort()
メソッドは実装されておらず、子クラスに実装が任されていました。
これを上記のように委譲(オブジェクトのメソッドに振る舞いを委譲すること)することで、柔軟な振る舞いをできるようにしています。
サンプルコードにて「関数は第一級オブジェクトである」を使用しています。