首页
学习
活动
专区
圈层
工具
发布
社区首页 >问答首页 >在Swift中创建通用领域存储库

在Swift中创建通用领域存储库
EN

Stack Overflow用户
提问于 2017-02-21 21:57:35
回答 2查看 3.2K关注 0票数 3

我一直在努力解决一个问题,我很确定这个问题会导致我采用Type-Erasure技术,但我不是100%确定。我尝试了几次,感觉很接近,但最终都失败了。我会试着简化我的问题。假设你有一个实体

代码语言:javascript
复制
struct Expense {
    var id: Int?
    var amount: Double = 0
}

和一个等价的领域对象

代码语言:javascript
复制
class RealmExpense: Object {
    let id = RealmOptional<Int>()
    let amount = RealmOptional<Double>()

    var entity: Expense {
        return Expense(id: id.value, amount: amount.value)
    }
}

注意,我可以使用entity变量将RealmExpense转换为Expense。

然后,我有了另一个协议

代码语言:javascript
复制
protocol ExpenseRepository: class {
    func getAll() -> [Expense]
    //...other CRUD methods
}

最后,还有一个类

代码语言:javascript
复制
class ExpenseRealmRepository: ExpenseRepository {
    
    private let realm = try! Realm()
    
    func getAll() -> [Expense] {
        return realm.objects(RealmExpense.self).flatMap { $0.entity }
    }

    func insert(item: Expense) {
        try! realm.write {
            realm.add(RealmExpense(expense: item))
        }
    }
    //...implementation of other CRUD methods
}

现在,这工作得很好,但是我有很多实体,这是我想重构的重复性代码,但我每次尝试创建这个泛型都会抛出这样或那样的编译器错误。我想要的是基本上能够创建一个类

代码语言:javascript
复制
class RealmRepository<RepositoryType: Object, EntityType> {

    private let realm = try! Realm()

    func getAll() -> [EntityType] {
        return realm.objects(RepositoryType.self).flatMap { $0.entity }
    }

    func insert(item: EntityType) {
        try! realm.write {
            realm.add(RepositoryType(item))
        }
    }
    //...the rest of the CRUD methods.
}

我的主要问题是似乎Swift泛型不允许这种类型的行为。也许有一种更好的整体方法,我还没有探索过。

注: Dave Weston答案的小附录如下:

David Weston在下面给出的答案是正确的(也是很好的),但目前有一个Swift错误,它阻止了领域实体初始化器的使用。请参见:

https://github.com/realm/realm-cocoa/pull/2514

基本上,解决方案是使用接受字典的领域对象的默认初始化器。因为我已经在使用JSON库在实体之间来回转换,所以这就像更改ObjectMapper一样简单

代码语言:javascript
复制
func insert(item: T.EntityType) {
    realm.write {
        realm.add(RealmEntityType(item))   //compiler error when initializing RealmEntityType
    }
}

代码语言:javascript
复制
func insert(item: T.EntityType) {
    let realmItem = RealmEntityType()         
    realmItem.setValuesForKeys(item.toJSON())  //needs to be a dictionary
    try! realm.write {
        realm.add(realmItem)
    }
}
EN

回答 2

Stack Overflow用户

回答已采纳

发布于 2017-02-22 06:23:21

这是一个有趣的问题。我不确定您将如何使用这些存储库对象,但根据您到目前为止的问题,我不需要使用类型擦除。

首先,我们定义所需的通用层次结构:

代码语言:javascript
复制
// implemented by your immutable structs
protocol Entity {
}

// Implemented by RealmSwift.Object subclasses
protocol RealmEntity {
    associatedtype EntityType

    init(_ entity: EntityType)
    var entity: EntityType { get }
}

// protocol to define the operations one can perform on a repository
protocol Repository {
    associatedtype EntityType

    func getAll() -> [EntityType]
    func insert(item: EntityType)
}

// A RealmRepository that implements the Repository protocol on top of Realm
class RealmRepository<T>: Repository where T: RealmEntity, T: Object, T.EntityType: Entity {
    typealias RealmEntityType = T

    private let realm = Realm()

    internal func insert(item: T.EntityType) {
        realm.write {
            realm.add(RealmEntityType(item))
        }
    }

    internal func getAll() -> [T.EntityType] {
        return realm.objects(T.self).flatMap { $0.entity }
    }
}

现在我们有了基础设施,我们可以创建一个ExpenseRepository来显示所有这些东西都是编译的:

代码语言:javascript
复制
struct Expense: Entity {
    var id: Int
    var amount: Double
}

class RealmExpense: Object, RealmEntity {
    typealias EntityType = Expense

    let id: RealmOptional<Int>
    let amount: RealmOptional<Double>

    required init(_ entity: EntityType) {
        id = RealmOptional(entity.id)
        amount = RealmOptional(entity.amount)
    }

    var entity: Expense {
        return Expense(id: id.value!, amount: amount.value!)
    }
}

var expenseRepository = RealmRepository<RealmExpense>()

这可能不会在你的项目中编译,因为我是在一个没有导入Realm的游乐场中创建的,但它应该会给你一个想法。

现在,如果您想存储不同类型的存储库的数组,或者是存储库类型的变量,那么就需要进行类型擦除,并且必须创建一个AnyRepository

票数 8
EN

Stack Overflow用户

发布于 2019-03-20 02:21:58

我正在尝试编写一个库,您可以在以下位置找到它:

https://github.com/rusito-23/RealmDAO

更新:

基本思想是在一个名为GenericDAO的类中处理所有领域事务,该类有两个关联的类型,一个从Object扩展,另一个从Transferrable扩展(这样我们可以处理对象的副本,而不是对象本身)。

还有一个额外的协议和他的方法来处理自动增量主键!

它应该像这样简单地使用:

代码语言:javascript
复制
let movieDAO = GenericDAO<Movie>()

movieDAO.findAll(completion: { /*-- YOUR CODE --*/})

你可以在我发送的链接上找到更多信息!

希望它能帮上忙!

票数 -1
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/42369333

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档