ООП для чайников. Паттерны проектирования. Адаптер (adapter)

С недавнего времени, мы в команде завели такую практику как обмен опытом. Сначала мы пробовали просто готовить доклады, на всякого рода интересные темы касающиеся технологий, практик и подходов. Но, этот подход не совсем себя оправдал, и мы стали готовить небольшие доклады на заранее оговоренные темы, например, — паттерны проектирования.

Идея состоит в том что мы выбираем несколько паттернов, делаем лаконичный пример использования, на каком-то языке не связанной с основной работой (php). Затем мы собираемся, показываем свои примеры, и обсуждаем конкретный паттерн и реализацию. Так у нас накопилось некоторое количество реализаций на Python, Ruby, Groovy. На самом деле, как мы потом убедились, выбор скриптового языка для иллюстрации паттерна, идея не очень хорошая, — нельзя выделить интерфейс, абстрактный класс, вследствие отсутствия строгой типизации смысл некоторых паттернов теряется, некоторые патерны трудно отличить один от другого. Наверное в дальнейшем мы ограничимся языками со строгой типизацией для паттернов, а скриптовые будем использовать для иллюстрации алгоритмов. Время покажет.

После столь долгого вступления, расскажу о первом паттерне Адаптер и примере его реализации на питоне. Этот паттерн относится к структурным паттернам (structural). Вот как он выглядит на диаграмме классов:

adapter

Этот паттерн используется в случае когда надо преобразовать интерфейс одного класса, в интерфейс другого, ожидаемого клиентом. Другими словами, — делает возможным работу классов с несовместимыми интерфейсами. В моем примере это какая-то, уже написанная и реализованная клиентская библиотека, использующая медленную библиотеку для взаимодействия с базой. новая библиотека отличается способом инициализации и вызова запросов. Используя адаптер, мы позволяем клиентской программе использовать новый движок баз данных, прозрачно для клиента, оставляя возможность использовать старый движок (если надо).

Код примера реализации паттерна:

 
class SlowDbEngine:
 
    def __init__(self, host, user, password, db):
        pass
 
    def runQuery(self, sql):
        return ["row1", "row2", "row3"]
 
class FastDbEngine:
 
    def __init__(self, connection):        
        pass        
 
    def query(self, sql):
        return range(3, 0, -1)
 
    def fetch(self, result):
        return "row%d" % (result.pop())
 
    def recordsCount(self, result):
        return len(result)
 
 
class DbAdapter:
 
    def __init__(self, host, user, password, db, type = "fast"):
        self._type = type
        if(type == "slow"):
            self._db = SlowDbEngine(host, user, password, db)
        else:
            self._db = FastDbEngine([host, user, password, db])
 
    def runQuery(self, sql):
        if self._type == "slow":
            return self._db.runQuery(sql)
        else:
            result = self._db.query(sql)                            
            return [self._db.fetch(result) for i in xrange(self._db.recordsCount(result))]
 
if __name__ == '__main__':   
    print(DbAdapter("localhost", "root", "password", "db").runQuery("select * from table"))
 
-----------------------
 
['row1', 'row2', 'row3']
 

Comments

comments


Bookmark and Share