【デザインパターン勉強】Decoratorメソッド

ざっくり概要

decoratorとは 装飾 の意味です。 あるコアクラスを元にして機能をかぶせていく手法です。

今回は簡略化のために1つのコア、一つの機能をかぶせた例を用いて説明します。

コード

class PlainNumber():
    def __init__(self,num):
        self._num = num
    
class MultiplicationNumber(PlainNumber):
    def __init__(self,num):
        self._number = num
    
    def render(self,num):
        return self._number.render() * num

    
if __name__ == '__main__':
    plain_num = PlainNumber(11)
    multiple_output = MultiplicationNumber(plain_num)
    print("11*2=",multiple_output.render(2)) # 11*2= 22
    

ざっくり解説

コードの流れは以下の通りです。

  1. 数字を設定(PlainNumberクラス)を設定
  2. 掛け算(MultiplicationNumber)機能を追加し
  3. 数字×掛け算を実行

MultiplicationNumberはPlainNumberを継承しているので掛け算が実行出来ますね。

現実的な利用シーン(個人的感想)

  • 長所

開発のシーンでは、最初に決めた仕様し、実装し、あとから機能追加といったことがあると思います。 そういった際、設計を変えずに追加することが出来て、便利なんじゃないでしょうか。

  • 短所

デコレートをしすぎると管理しづらい気がします。(意図せず重複した機能を持ったクラスを追加するなど)そこらへんは長所とトレードオフな気がしますが

参考文献

Javaで学ぶデザインパターン入門 https://github.com/faif/python-patterns/blob/master/structural/decorator.py

【デザインパターン勉強】Facadeメソッド

ざっくり概要

Facade(建物の正面)という意味を指しています。 このパターンは内部の処理を簡素化したクラスを一つにすることで、複雑な処理を見せないメソッドです。

自分なりの言葉で言うと、処理を一つのクラスに集約したら見通して良くなって、すぐわかるんじゃね? ということです。

コード

ココのコードを利用して説明します。

import time

class TC1:
    
    def run(self):
        print("test1")
        print("settup")
        print("finish")
        time.sleep(0.1)

class TC2:
    
    def run(self):
        print("test2")
        print("settup")
        print("finish")
        time.sleep(0.1)

        
class TC3:
    
    def run(self):
        print("test3")
        print("settup")
        print("finish")
        time.sleep(0.1)

class TestRunner:
    
    def __init__(self):
        self.tc1 = TC1()
        self.tc2 = TC2()
        self.tc3 = TC3()
        self.tests = [self.tc1,self.tc2,self.tc3]
    
    def runAll(self):
        [i.run() for i in self.tests]

if __name__ == '__main__':
    testrunner = TestRunner()
    testrunner.runAll()

ざっくり解説

TestRunnerクラス

このクラスで処理をまとめています。 具体的にはTC1~3で標準出力するメッドをrunAllに集約しています。

今回はTC1~TC3という3つのクラスのメソッドを用いて集約してますが、 もっと複雑なケースを考えてみます。

  • そのままAクラスはインスタンス化して、
  • Aのメソッドを呼び出し
  • Bクラスメソッドを使って

・・・C、D、E、F、Gの処理へ続く。

といったケースですと、複雑で何しているかわからなくなりますね。

一つのクラス(窓口)に集約化することで見通しが良くなります。 クラス名もわかりやすく(例えば、MakeCSV具体的な作業を明示) とか、わかりやすくすれば初見の人でも通りやすくなるんじゃないでしょうか。

利用方法

個人開発をしている人にはあまり実りのあるメソッドとはいえないと思います(処理の流れをわかっているため)。 しかしながら、何人も関わっている開発プロダクトの場合、は必須のパターンだと思います。

参考文献

Javaで学ぶデザインパターン入門

【デザインパターン勉強】Singletonメソッド

ざっくり概要

このパターンの目的は 一つのクラスに複数のインスタンスを作らないようにすることです。

利用シーン... パスワード管理のメソッドなど管理が厳重にする必要があるメソッドを管理する時に使うんでしょうかね。。

コード

class Singleton:
    initial_class_name = None
    
    # クラスインスタンス化した際、__new__→__init__が呼び出される。
    def __init__(self):
        print("init")
    
    def __new__(self):
        
        if Singleton.initial_class_name is None:
            print("new")
            Singleton.initial_class_name = super().__new__(self)
        
        return Singleton.initial_class_name

if __name__ == '__main__':
    a = Singleton() #こんな感じで出力→<__main__.Singleton object at 0x106614438>
    b = Singleton() #↑と同じ。<__main__.Singleton object at 0x106614438>
    print(a)
    print(b)
    print(a is b)
    

ざっくり解説。

classをインスタンス化した際にクラス変数(initial_class_name)をつけておくことで フラグ(インスタンスを生成したかどうか)として機能させています。

今回は参考URLが非常に秀逸だったのであまり語ることはないです。。

参考URL

http://blanktar.jp/blog/2016/07/python-singleton.html

【デザインパターン勉強】adapterメソッド

ざっくり概要

adapterメソッドとはざっくり言うと既に 提供されているclassと既に必要な抽象classを結びつけてプログラムを作成する方法です。 ポイントは、仲介役classを設定(提供されているclassと必要な抽象class)することです。

登場メソッド

必要な抽象メソッド(抽象classに存在)

  • make_csv(CSVファイル内容作成)
  • make_txt(TXTファイル内容作成)

提供されているメソッド(提供されているclass)

  • make_file_csv(CSVファイル書き込み)
  • make_file_txt(TXTファイル書き込み)

本来であれば・・・

抽象classと提供されているclassのメソッドを同一化すれば問題ないです が、 今回は 所々の事情で 修正出来ないケースを想定しています。

コード

#python3.5.2
import abc
import os
import csv

class Format:
    def __init__(self,content):
        self.__content = content
    
    def make_file_csv(self,file_name):
        f = open('{}.csv'.format(file_name),'w')
        f.write(self.__content)
    
    def make_file_txt(self,file_name):
        f = open('{}.txt'.format(file_name),'w')
        f.write(self.__content)


class TextMake(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def make_csv(self):
        pass
    
    @abc.abstractmethod
    def make_txt(self):
        pass

class TextMakeFormat(TextMake,Format):
    def __init__(self,content):
        super().__init__(content)
    
    def make_csv(self,file_name):
        self.make_file_csv(file_name)
    
    def make_txt(self,file_name):
        self.make_file_txt(file_name)


if __name__ == '__main__':
    textobj = TextMakeFormat('おはようございます。\n今日も元気で頑張りましょう。')
    textobj.make_csv("csv_file") #TextMakeFormatを経由してcsvファイル作成
    textobj.make_txt("txt_file") #TextMakeFormatを経由してtxtファイル作成

各クラスの概要

Format(提供されているclass)

具体的処理メソッド(csv txtファイル作成)が記述されています。

TextMake(必要な抽象クラス)

既に必要とされているケースであり、メソッド(≠Formatのメソッド)が記述されています。

TextMakeFormat(仲介役)

FormatとTextMakeクラスの仲介役をします。 具体的には以下の手順となります。

    1. TextMake(必要な抽象クラス)をオーバーライドしてメソッドを宣言
    1. オーバーライドしたメソッドにFormat(提供されているclass)のメソッドを記述 これにより、必要な抽象class→提供されているClassの仲介を果たします。

感想

理解不足もあるかもしれませんが、利用シーンがあまり思い浮かびませんでした。。

参考文献

Javaで学ぶデザインパターン入門

【デザインパターン勉強】builderメソッド

ざっくり概要

builderメソッドを自分の言葉でいうと、

作成するメソッドの役割は同じだが、異なる結果を得るプログラムを何個も 作る際、有用なプログラム(パターン) といった感じです。

ここで重要な点は 作成するメソッドの役割は同じ ということです。

本記事で記載したコードは税計算を表示するプログラムです。

登場メソッド

  • set_total(金額インプット)
  • set_tax(税率インプット)
  • message_tax(消費税を計算、出力)

コード

# python3.5.2
import abc

class TaxCalcDirector():
    def __init__(self, builder):
        self.__builder = builder
        
    def construct(self,total,tax):
        self.__builder.set_total(self,total)
        self.__builder.set_tax(self,tax)
        self.__builder.message_tax(self)

class AbstractTaxCalcBuilder(metaclass=abc.ABCMeta):
    @abc.abstractmethod
    def set_total(self,total):
        pass

    @abc.abstractmethod
    def set_tax(self,rate):
        pass
        
    @abc.abstractmethod
    def message_tax(self,message):
        pass
    
class ConsumptionTaxBuilder(AbstractTaxCalcBuilder):
    def __init__(self):
        self.rate = 0
        self.total = 0
        
    def set_total(self,total):
        self.total = total
        
    def set_tax(self,rate):
        self.rate = rate
    
    def message_tax(self):
        tax = self.total * self.rate
        message = " ".join(["あなたの払う税金は",str(tax),"円です"])
        print(message)
        
class DeductionTaxBuilder(AbstractTaxCalcBuilder):
    def __init__(self):
        self.rate = 0
        self.total = 0
        
    def set_total(self,total):
        self.total = total
        
    def set_tax(self,rate):
        self.rate = -1 * rate
    
    def message_tax(self):
        tax = self.total * self.rate
        message = " ".join(["あなたが還付される税金は",str(tax),"円です"])
        print(message)

def main():
    # 支払う税金
    tax = TaxCalcDirector(ConsumptionTaxBuilder)
    tax.construct(1000,0.3) #あなたの払う税金は 300.0 円です
    # 還付
    tax = TaxCalcDirector(DeductionTaxBuilder)
    tax.construct(200,0.1) #あなたが還付される税金は -20.0 円です

    
if __name__ == '__main__':
    main()    

main()メソッドでは、行いたい作業(クラス名)をインスタンス化しています。 作業に応じて、 tax = TaxCalcDirector(クラス) #クラス→ ConsumptionTaxBuilderやDeductionTaxBuilder とすることで、クラスの継承を変えて、税の還付金計算に変更することが出来ます。 つまり、具体的な作業を認識せずに処理を変えられます。 今回は消費税計算、税の還付金計算と処理を変えています。

各クラスの役割

AbstractTaxCalcBuilder(Builder)

インスタンスを作成する際に必要な作業(メソッド)を規定しています。 つまり、以下のメソッドとなります。

  • 金額インプット set_total
  • 税率インプット set_tax
  • 消費税を計算、出力 message_tax

メソッドをオーバーライドし忘れを防ぐために抽象クラスとしています。 教科書では Builder と呼ばれますが、「現場監督」といったほうがイメージしやすい気がします。

ConsumptionTaxBuilder(ConcreteBuilder)

AbstractTaxCalcBuilderで定義されたメソッドを具体化しています。

教科書では ConcreteBuilder と呼ばれますが「現場作業員」といったほうがイメージしやすい気がします。

TaxCalcDirector(Director)

AbstractTaxCalcBuilderのメソッドを用いてインスタンスを生成しています。 また、インスタンス作成の際、ConsumptionTaxBuilder継承してインスタンス化しています。

必要な情報は builderのメソッドとConsumptionTaxBuilderというConcreteBuilder のクラス名のみです。

ここで、重要なのは以下の2点です。

  • AbstractTaxCalcBuilder(Builder)のメソッドのみを使っていること
  • 具体的なアウトプットを得る際はConcreteBuilderのクラス名を継承して実行

教科書では Directorと呼ばれて説明されています。監督する立場なのでイメージしやすいですね。

ここでわかることは アウトプットを変更する際、ConcreteBuilderクラス名を修正して実行すればいい

→つまり、クラス名だけで柔軟にアウトプットを変えることが出来るということです。

参考文献

Javaで学ぶデザインパターン入門

Rails でログロテート

久しぶりにrubyネタ

知らない間に自分が作ったサービスが止まっていた件

サービス

確認してみたら定期的にproduction logを削除していなかった。。。

  config.logger = Logger.new("log/production.log", 5, 10*1024*1024)
  #第一引数ログパス、第二引数は保存するファイル数、第三引数は容量
  #古いログは削除されていく

参考

どーでも良いけど

個人的にはshellスクリプトで定期的に削除するプログラムを cronに登録した方がわかりやすい

【Pythonメモ】collectionsモジュール

 # collectionsモジュール勉強
import collections

#counterメソッドはカウント系メソッド
c = collections.Counter()
c['spam'] += 1
c[100] += 1
c[200] += 2
c[200] += 3
# Counter({200: 5, 'spam': 1, 100: 1})
print(type(c))
c2 = collections.Counter()
c2['spam'] = 1
c2[200] = 1

print(c & c2) #Counter({200: 1, 'spam': 1})
print(c + c2) #Counter({200: 6, 'spam': 2, 100: 1})

# ChainMapはdict
d1 ={'spam':1}
d2 ={'ham':2}
d = collections.ChainMap(d1,d2)
print(d)