如何重构swift代码以将协议和结构类型作为方法参数

时间:2016-03-23 17:07:04

标签: ios swift

我有两个有很多共同点的函数,我想重新考虑我的代码来删除重复的逻辑,但是不同的东西是类型,特别是协议和结构类型。我现在可以考虑的方法是重新考虑这个问题我有一个常用方法,它将一个协议类型作为参数,一个结构类型,其结构类型必须实现协议'DataDictionaryStore' 。并将返回作为参数1

传入的协议类型的数组

我试图用泛型来实现它,但是根据我的理解,你仍然在使用泛型时将实例作为参数传递,而不是实际的类型本身。

我想在下面的代码中重新考虑的方法是'articles()'和'authors()'

这是代码(可以复制到游乐场Xcode 7 +):

import Foundation

protocol Article {
    var headline: NSString? { get }
}

protocol Author {
    var firstName: NSString? { get }
}

protocol DataDictionaryStore {

    init(dataDictionary: NSDictionary)
}

struct CollectionStruct {

    let arrayOfModels: [NSDictionary]

    //This function is identical to authors() except for return type [Article], and 'ArticleStruct'
    func articles() -> [Article] {

        var articlesArray = [Article]()

        for articleDict in arrayOfModels {
            let articleStruct = ArticleStruct(dataDictionary: articleDict)
            articlesArray.append(articleStruct)
        }
        return articlesArray
    }

    func authors() -> [Author] {

        var authorsArray = [Author]()

        for authorDict in arrayOfModels {
            let authorStruct = AuthorStruct(dataDictionary: authorDict)
            authorsArray.append(authorStruct)
        }
        return authorsArray
    }
}

struct ArticleStruct : Article, DataDictionaryStore {

    var internalDataDictionary: NSDictionary
    init(dataDictionary: NSDictionary) {
        internalDataDictionary = dataDictionary
    }
    var headline: NSString? { return (internalDataDictionary["headline"] as? NSString) }
}

struct AuthorStruct : Author, DataDictionaryStore {

    var internalDataDictionary: NSDictionary
    init(dataDictionary: NSDictionary) {
        internalDataDictionary = dataDictionary
    }
    var firstName: NSString? { return (internalDataDictionary["firstName"] as? NSString) }
}

var collStruct = CollectionStruct(arrayOfModels: [NSDictionary(objects: ["object1", "object2"], forKeys: ["key1", "headline"])])

print(collStruct)
var articles = collStruct.articles()
print(articles)
for article in articles {
    print(article.headline)
}

如果有另一种方法可以重新考虑这个以消除重复的逻辑,欢迎提出所有建议。

2 个答案:

答案 0 :(得分:1)

这不完全是你问题的答案,但这可能会简化它,让你开心:

router.HandleFunc("/{adapter:(s3|onedrive)}/{schema:[a-z]+}/check",
func(w http.ResponseWriter, r *http.Request) {
    w.Write([]byte(fmt.Sprintf(`{"a":"%s","s":"%s"}`,
        mux.Vars(r)["adapter"], mux.Vars(r)["schema"])))
}).Methods("GET")

答案 1 :(得分:1)

根据PEEJWEEJ的答案,这个重构也值得一试。您可以返回作者和文章的元组,而不是返回单个数组。如果您不打算同时处理作者和文章数组,则此方法更昂贵。但是语法比以前使用泛型的解决方案好得多。

  func allObjects() -> (authors: [AuthorStruct], articles: [ArticleStruct]) {
    let authors = arrayOfModels.map(AuthorStruct.init)
    let articles = arrayOfModels.map(ArticleStruct.init)
    return(authors, articles)
  } 

然后你会调用这样的方法:

let objects = collection.allObjects()
let authors = objects.authors
let articles = objects.articles

我不是这里清晰度的忠实粉丝,但也许你可以稍微重构一下。它似乎至少起作用。

func allObjectsOfType<T>(type: T.Type) -> [T] {

   var objectArray = [T]()

   for objectDict in arrayOfModels {
      var objectStruct: T?

      if type == Author.self {
        objectStruct = AuthorStruct(dataDictionary: objectDict) as? T
      } else if type == Article.self {
        objectStruct = ArticleStruct(dataDictionary: objectDict) as? T
      }

      guard objectStruct != nil else {
        continue
      }

      objectArray.append(objectStruct!)
   }

   return objectArray
}

然后你可以这样称呼它......

collection.allObjectsOfType(Author)
collection.allObjectsOfType(Article)