Maury Markowitz
Maury Markowitz

Reputation: 9279

Swift initializer with different name than class?

I think the answer is "don't do that", but here goes... Consider:

class Enemy {
   var name: String
   var type: Int
   init(ofType: Int) {
       type=ofType
   }
}

I have two types of enemies, friends=0 and closeFriends=1. One's enemies might switch between these at any time. So:

var newEnemy = Enemy(ofType:.closeFriend)
newEnemy.name = "Bob"

and perhaps at some time in the future:

newEnemy.type = .friend

But I find this syntax somewhat opaque. For the same reason that it's better to use an enum instead of an Int, your intentions are much more clear if you make new objects that directly represent their type, perhaps:

var newEnemy = CloseFriend(withName:"Bob")

Normally this requires subclassing Friend and CloseFriend, but then one cannot simply turn a Friend into a CloseFriend.

typealias seems like it might be a solution, I could alias Enemy to Friend and CloseFriend. But that doesn't add a new init that sets the type based on the alias. For instance, CloseFriend() should set the type to 1 without it having to be specified. Is there a way to do that?

Upvotes: 0

Views: 401

Answers (2)

Cristik
Cristik

Reputation: 32783

Well, if the same person becomes changes from a friend to a close friend, it makes perfect sense to reuse the same instance. Just like it would happen in the real life, when relationships between people change (you don't get someone's clone if that person starts hating you and wants to destroy you).

What you could improve, architecturally speaking, is to merge the "skills" and the type of the enemy. E.g.:

class Enemy {
    var name: String
    var traits: Traits

    enum Traits {
        case friend(FriendTraits)
        case closeFriend(CloseFriendTraits)
    }

    struct FriendTraits { ... }
    struct CloseFriendTraits { ... }
}

This way you can simply change the type, while preserving the other attributes (and if you're developing a game the other attributes might be important).

Upvotes: 0

Sulthan
Sulthan

Reputation: 130102

This is rather simple to do using a function but I would really advise against it:

class Enemy {
    enum EnemyType: Int {
        case friend
        case closeFriend
    }

    var name: String
    var type: EnemyType

    init(type: EnemyType, name: String = "") {
        self.type = type
        self.name = name
    }
}

// let's make a function that looks like creating new object
func CloseFriend(name: String) -> Enemy {
    return Enemy(type: .closeFriend, name: name)
}

Such "smart" things completely destroy the readability of your code. There is nothing more readable than writing:

Enemy(type: .closeFriend, name: "Bob")

There is no reason to save a few letters of code.

Sure, you could create a factory function

extension Enemy {
    static func closeFriend(name: String) -> Enemy {
        return Enemy(type: .closeFriend, name: name)
    }
}

but is it really better to call:

Enemy.closeFriend(name: "Bob")

vs

Enemy(type: .closeFriend, name: "Bob")

?

Upvotes: 1

Related Questions