使用函数式编程重构

DRY(Don’t repeat yourself)原则是编程中的一个基本原则。这个原则强调在编程过程中避免重复的代码片段,以减少代码的冗余,提高代码的可维护性和可读性。遵循DRY原则,可以使代码更加简洁、易于理解和修改。有很多设计模式可以用于实现DRY原则,比如模板模式,就是为了复用执行步骤。可仍然有很多情况,虽然重复代码很多,但如果只使用传统的面向对象编程技术,却很难对这些代码进行重构。我们看下面一个例子:

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
const config = require('config');
var MongoClient = require('mongodb').MongoClient;

const mongosettingsurl = process.env.mongo_url || config.mongo.url
const mongosettingsdb = process.env.mongo_db || config.mongo.db
const LeaveApply = require("../domain/leaveApply")

class MongoRepository {
constructor() {

}

//保存请假申请
async save(leaveApply) {
var mongodb = await MongoClient.connect(mongosettingsurl);
var dbase = mongodb.db(mongosettingsdb);
var collection = dbase.collection("leave_apply");
const obj = await this.get(leaveApply.id)
if (!obj) {
await collection.insertOne(leaveApply)
} else {
await collection.deleteMany({ id: leaveApply.id })
await collection.insertOne(leaveApply)
}
mongodb.close()
}

//删除请假申请
async remove(id) {
var mongodb = await MongoClient.connect(mongosettingsurl);
var dbase = mongodb.db(mongosettingsdb);
var collection = dbase.collection("leave_apply");
await collection.deleteMany({ id: id })
mongodb.close()
}

//根据id获取请假申请
async get(id) {
var mongodb = await MongoClient.connect(mongosettingsurl);
var dbase = mongodb.db(mongosettingsdb);
var collection = dbase.collection("leave_apply");
var instance = await collection.findOne({ id: id })
const obj = instance ? LeaveApply.fromJSON(instance) : null
mongodb.close()
return obj
}


async getItems(condition){
var mongodb = await MongoClient.connect(mongosettingsurl);
var dbase = mongodb.db(mongosettingsdb);
var collection = dbase.collection("leave_apply");

const lst= await collection.find(condition).toArray()

mongodb.close()
return lst
}
}

module.exports = MongoRepository

上面的代码中,每个函数的执行过程基本相同,都是需要先连接数据库,进行操作,然后关闭数据库,并返回结果。如果采用一般的方式,我们需要定义一个复合对象,这个对象中包括collection和mongodb,再创建一个函数,这个函数用于返回这个对象,当执行具体方法时,首先获取复合对象,然后进行相应的操作。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
async getDbObject(){
var mongodb = await MongoClient.connect(mongosettingsurl);
var dbase = mongodb.db(mongosettingsdb);
var collection = dbase.collection("leave_apply");
return {mongodb:mongodb,collection:collection}
}

async getItems(condition){
var dbObj=this.getDbObject()
const lst= await dbObject.collection.find(condition).toArray()
dbObject.mongodb.close()
return lst
}

还有一种办法是采用函数式编程,这种方式类似于模板方法,将需要具体完成的工作以函数形式传入。

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
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
var MongoClient = require('mongodb').MongoClient;

const LeaveApply = require("../domain/leaveApply")

class MongoRepository {
constructor(mongosettingsurl,mongosettingsdb) {
this.mongosettingsurl=mongosettingsurl
this.mongosettingsdb=mongosettingsdb
this.collectionName="leave_apply"
}

//没有返回结果
async dbAction(callback) {
var mongodb = await MongoClient.connect(this.mongosettingsurl);
var dbase = mongodb.db(this.mongosettingsdb);
var collection = dbase.collection(this.collectionName);
await callback(collection)
await mongodb.close()
}

//有返回结果
async dbFunction(callback) {
var mongodb = await MongoClient.connect(this.mongosettingsurl);
var dbase = mongodb.db(this.mongosettingsdb);
var collection = dbase.collection(this.collectionName);
const res = await callback(collection)
await mongodb.close()
return res
}

//保存请假申请
async save(leaveApply) {
const me = this
await this.dbAction(async function (collection) {
const obj = await me.get(leaveApply.id)
if (!obj) {
await collection.insertOne(leaveApply)
} else {
await collection.deleteMany({ id: leaveApply.id })
await collection.insertOne(leaveApply)
}
})
}


//删除请假申请
async remove(id) {
const me = this
await this.dbAction(async function (collection) {
await collection.deleteMany({ id: id })
})
}

//根据id获取请假申请
async get(id) {
const me = this
const res = await this.dbFunction(async function (collection) {
var instance = await collection.findOne({ id: id })
const obj = instance ? LeaveApply.fromJSON(instance) : null
return obj;
})
return res
}

async getItems(condition) {
const me = this
const res = await this.dbFunction(async function (collection) {
const lst = await collection.find(condition).toArray()
return lst
})
return res
}
}

module.exports = MongoRepository

比起第一种方法,这种方法更通用一些,也更安全一些,因为在这种方式中执行操作没有离开数据库操作范畴,如果有类似工作单元的操作不会出现问题,而第一种方式只是针对特定的情况。