我需要构建一个抽象层来存储我们的应用程序。数据将保存在dynamoDB,S3,Mongo或Mysql中(这可能会改变)。我们的应用程序将收到GET和POST请求。应用程序将触及抽象层,该层应决定当前使用的数据存储是什么,并应保存或从当前存储中获取数据。我们应该可以灵活地在任何时候更改存储,只需对代码进行最小的更改。设计这个抽象层的最佳方法是什么?
答案 0 :(得分:2)
这是典型的策略和工厂设计模式。
您将拥有抽象Storage
,并且您要实施的任何内容都将遵循相同的合同(例如MongoDBStorage
,CassandraStorage
)。
我实际上会创建NoSQLStorage
和RelationalStorage
作为单独的抽象,但在相同的Storage
下,因为它们的数据结构可能不同,因为关系中的One to Many表大多数时间只变为一个NoSQL中的表/集合。这可能会增加非常不受欢迎和不必要的复
同样,S3与Relational或NonRelational的存储不同,我会毫不犹豫地用一把刀解决所有类型的问题。 (但为了简单起见,我假设他们接受类似的输入。)
在每个策略的内部,您必须包装实际的存储API,并简单地将输入转换为实际存储API支持的输入。例如,您必须为MongoDB将StorageRecord
翻译为DBObject
。
设计非常粗略,如下所示,我使用scala lang进行设计,你绝对可以使用任何OO lang。
将向客户提供的存储抽象
trait Storage {
def insert(record: StorageRecord): Boolean
def query(query: Query): List[StorageRecord]
def update(updateCondition: Query, updateQuery: Query)
def delete(deleteCondition: Query)
}
trait RelationalStorage extends Storage
trait StorageRecord
trait Query
trait NoSQLStorage extends Storage
<强>实现强>
class MongoDBStorage extends NoSQLStorage {
override def insert(record: StorageRecord): Boolean = ???
override def query(query: Query): List[StorageRecord] = ???
override def update(updateCondition: Query, updateQuery: Query): Unit = ???
override def delete(deleteCondition: Query): Unit = ???
}
class DynamoDBStorage extends NoSQLStorage {
override def insert(record: StorageRecord): Boolean = ???
override def query(query: Query): List[StorageRecord] = ???
override def update(updateCondition: Query, updateQuery: Query): Unit = ???
override def delete(deleteCondition: Query): Unit = ???
}
客户将调用的StorageFactory获得正确的Storage
。
class NoSQLStorageFactory {
def getStorage(config: String): Storage = {
config match {
case "MongoDB" => new MongoDBStorage
case "DynamoDB" => new DynamoDBStorage
case _ => throw new Exception("Storage not configured")
}
}
}
客户端代码如下所示,您可以将存储服务器,数据库名称,存储驱动程序作为可配置属性,只需更改配置即可使其正常工作。
val storage = applicationConfig.get("storage.driver")
val storage = new NoSQLStorageFactory().getStorage(storage)
storage.insert(instanceOfYourStorageRecord)