模版模式一般利用继承实现。比如我们有不同的任务要完成,其中有一些任务是相同的,我们可以将这些任务放在公共的基类中完成,其余特殊的任务设计在子类中。
这是设计模式系列文章的一部分,点击查看该系列的其他文章。
模版模式有助于去除重复代码,并满足了”DRY-不要重复自己“原则。
平时遇到数据处理的需求,我们需要执行一些常见的任务,如:
- 去数据库取数,并将某些结果打印至控制台
- 去数据库取数,简单处理后,将结果保存到 csv 文件
在这两个步骤中,有些子步骤是一样的,比如连接数据库,发出查询请求,执行 query 语句等。
可以将这部分功能集成到基类中,而其他特殊的功能可以放到子类中。
我们举例来说明,首先准备一个数据库。
1 2 3 4 5 6 7 8 9 10 11 12 13 14
| import sqlite3
conn = sqlite3.connect("sales.db") conn.execute( "CREATE TABLE sales" "(" "salespersion txt," "amt currency," "year integer," "model text," "new boolen" ")" )
|
插入一些假数据:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23
| conn.execute("delete from sales")
conn.execute( "insert into sales values" "('Scott', 1400, 2007, 'Toyota', 'false')" ) conn.execute( "insert into sales values" "('Desmond', 1600, 2010, 'Honda fit', 'true')" ) conn.execute( "insert into sales values" "('Burney', 1600, 2010, 'Honda fit', 'true')" ) conn.execute( "insert into sales values" "('Austin', 1600, 2010, 'Honda fit', 'true')" )
cursor = conn.execute("select * from sales") cursor.fetchall()
|
查询结果输出如下:
1 2 3 4
| [('Scott', 1400, 2007, 'Toyota', 'false'), ('Desmond', 1600, 2010, 'Honda fit', 'true'), ('Burney', 1600, 2010, 'Honda fit', 'true'), ('Austin', 1600, 2010, 'Honda fit', 'true')]
|
现在我们设计一个 query 的模版类,想想它需要有哪些功能?
一个可能的基类是这样的:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29
| class QueryTemplate: def connect(self): pass
def construct_query(self): pass
def do_query(self): pass
def format_results(self): pass
def output_results(self): pass
def process_format(self): """暴露给外部调用的方法,用来保证每个方法按照顺序执行。 """ self.connect() self.construct_query() self.do_query() self.format_results() self.output_results()
|
基类定义了我们需要有哪些功能,现在根据我们的需求,将其中一些可以共用的代码实现:
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27
| class QueryTemplate: """这个类提供了连接数据库、执行 query,格式化结果的功能 而对于构造 query、导出结果的功能,则抽象成接口交给子类去实现 """ def connect(self): self.conn = sqlite3.connect("sales.db")
def construct_query(self): raise NotImplementedError()
def do_query(self): result = self.conn.execute(self.query) self.result = result.fetchall()
def format_result(self): output = [] for row in self.result: row = [str(i) for i in row] output.append(row) self.formated_result = '\n'.join(output)
def output_result(self): raise NotImplementedError()
|
现在实现我们自己的需求就很容易了,因为我们只需要将精力放在构造 query 和 输出结果这两个方法上。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18
| class NewVehiclesQuery(QueryTemplate): def construct_query(self): self.query = "select * from sales where new = 'true'"
def output_result(self): print(self.format_result)
class OtherQuery(QueryTemplate): def construct_query(self): self.do_query = "select * from sales"
def output_result(self): file_name = "output_file.csv" with open (file_name, 'w') as file: file.write(self.formated_result)
|