Khawer K
Khawer K

Reputation: 105

Is there a way to encapsulate certain properties in a Swift protocol so they aren't visible to users of the protocol?

I am looking for a way to encapsulate certain properties in a Swift protocol to hide them from users of the protocol while making them available to types implementing the protocol.

Here is a simple illustrative example.

Say we are implementing the Command pattern, as shown below:

protocol Command {
    func execute()
}

class OneCommand: Command {
    private let target: CommandTarget
    
    init(target: CommandTarget) {
        self.target = target
    }
    
    func execute() {
        target.number = 1
    }
}

class TwoCommand: Command {
    private let target: CommandTarget
    
    init(target: CommandTarget) {
        self.target = target
    }
    
    func execute() {
        target.number = 2
    }
}

To enable these commands to undo themselves, the standard method is to have each command save the state of the target object before performing its action in the execute() method. The undo() method can then restore the state of the target object using this saved state.

Since the undo action is the same for all commands, one would want to implement it only once in an extension to the protocol. To be able to do that, however, both the variable in which the state is saved and the variable which stores a reference to the target object cannot be private since a protocol cannot have private properties.

The protocol will change as shown below:

protocol Command {
    var target: CommandTarget { get }
    var savedState: Int? { get set }
    func execute()
    func undo()
}

Each concrete command will have to be rewritten as follows:

class OneCommand: Command {
    let target: CommandTarget
    var savedState: Int?
    
    init(target: CommandTarget) {
        self.target = target
    }
    
    func execute() {
        savedState = target.number
        target.number = 1
    }
}

The undo() method can then be added through an extension to the protocol.

extension Command {
    func undo() {
        guard let savedState else { return }
        target.number = savedState
    }
}

This, however, also exposes the target and savedState properties to users of the protocol, exposing parts of the implementation of the protocol, which is not the intention.

Is there a way in Swift which would make the target and savedState properties available to types implementing the protocol, and in extensions to the protocol, without exposing them to users of the protocol.

Thanks for the help.

Upvotes: 0

Views: 39

Answers (0)

Related Questions