代码之家  ›  专栏  ›  技术社区  ›  Michael Abrams

初始化具有多个字段的结构的优雅解决方案

  •  0
  • Michael Abrams  · 技术社区  · 3 年前

    在我的程序中,我试图找到一个优雅的解决方案来初始化用户结构。我面临的问题是,我有很多很多领域,这些领域使得初始化用户变得庞大而混乱。有一件事可能会有所帮助:

    1. 当用户首次注册到应用程序时,我希望某些字段具有默认值,如个人简历、学校、个人信息等(因为他们还没有机会填充数据)

    我已经尝试过将其他结构包裹在字段中,以减少类的混乱,但这似乎仍然是一项糟糕的工作。

    public struct User {
        
        //MARK: - Fields
    
        var email: String
        var userSettings: UserSettings
        var userProfile: UserProfile
        var uid: String
        
        
        init?(with userNode: [String: Any]) {
            
            guard let userProfile = UserProfile(userNode: userNode),
                  let userSettings = UserSettings(userNode: userNode),
                  let email = userNode[EMAIL] as? String,
                  let uid = userNode[UID] as? String else { return nil }
            
            self.userProfile = userProfile
            self.userSettings = userSettings
            self.email = email
            self.uid = uid
    
        }
        
        /**
            Initalize a new user with credentials. Will initalize user with default settings and profile
         */
        init?(with credentials: AuthCredentials,
              profileDownloadUrl: [String],
              uid: String) {
            
            guard let birthday = credentials.birthday,
                  let firstName = credentials.firstName,
                  let lastName = credentials.lastName,
                  let gender = credentials.gender,
                  let preference = credentials.preference,
                  let geoHash = credentials.location?.geoHash,
                  let latitude = credentials.location?.latitude,
                  let longitude = credentials.location?.longitude,
                  let email = credentials.email else {
                return nil
            }
            
            //Create default profile
            self.userProfile = UserProfile(birthday: birthday,
                                             profilePictures: profileDownloadUrl,
                                             firstName: firstName,
                                             lastName: lastName)
            //Create default settings
            self.userSettings = UserSettings(minSeekingAge: MAX_AGE,
                                             maxSeekingAge: MIN_AGE,
                                             distanceRange: MAX_DISTANCE_RANGE,
                                             gender: gender,
                                             preference: preference,
                                             geoHash: geoHash,
                                             latitude: latitude,
                                             longitude: longitude)
            
            //Assign email
            self.email = email
            
            //Assign user id
            self.uid = uid
    
        }
    
    }
    

    建议使用什么设计模式?我已经研究了构建器的设计模式,但我个人并不喜欢,因为我仍然需要手动设置尽可能多的字段。

    0 回复  |  直到 3 年前
        1
  •  0
  •   rob mayoff    3 年前

    您可以通过引入 Error 类型,以及引发该错误的辅助函数:

    struct MissingField: Error { }
    
    func missingField<R>() throws -> R { throw MissingField() }
    

    具有 missingField ,您可以按照以下行重写每个inits:

        init?(userNode: [String: Any]) {
            do {
                userProfile = try UserProfile(userNode: userNode) ?? missingField()
                userSettings = try UserSettings(userNode: userNode) ?? missingField()
                email = try userNode[EMAIL] as? String ?? missingField()
                uid = try userNode[UID] as? String ?? missingField()
            } catch {
                return nil
            }
        }
        
        init?(
            credentials: AuthCredentials,
            profileDownloadUrl: [String],
            uid: String
        ) {
            do {
                userProfile = try UserProfile(
                    birthday: credentials.birthday ?? missingField(),
                    profilePictures: profileDownloadUrl,
                    firstName: credentials.firstName ?? missingField(),
                    lastName: credentials.lastName ?? missingField()
                )
                
                userSettings = try UserSettings(
                    minSeekingAge: MAX_AGE,
                    maxSeekingAge: MIN_AGE,
                    distanceRange: MAX_DISTANCE_RANGE,
                    gender: credentials.gender ?? missingField(),
                    preference: credentials.preference ?? missingField(),
                    geoHash: credentials.geoHash ?? missingField(),
                    latitude: credentials.latitude ?? missingField(),
                    longitude: credentials.longitude ?? missingField()
                )
                
                email = try credentials.email ?? missingField()
                self.uid = uid
            } catch {
                return nil
            }
        }