-->

Information Hiding the “Swifter” way?

2019-03-22 07:02发布

问题:

I have a question regarding object oriented design principles and Swift. I am pretty familiar with Java and I am currently taking a udacity course to get a first hands on in Swift.

In the Java community (basically in every community that follows OOP) it is very common to use information hiding techniques such as hiding or encapsulating data within classes to make sure it cannot be manipulated from outside. A common principle is to declare all attributes of a class as being private and use getters for retrieving an attribute's value and setters for manipulation.

I tried to follow this approach when writing a class that was part of the course and it looks like this:

//
//  RecordedAudio.swift
//  Pitch Perfect
//

import Foundation

class RecordedAudio: NSObject {
    private let filePathUrl: NSURL!
    private let title: String?

    init(filePathUrl: NSURL, title: String?)
    {
        self.filePathUrl = filePathUrl
        self.title = title
    }

    func getFilePathUrl() -> NSURL
    {
        return filePathUrl
    }

    func getTitle() -> String
    {
        if title != nil
        {
            return title!
        }
        else
        {
            return "none"
        }
    }
}

The code works and my private attributes cannot be accessed from outside my class, which is exactly the behavior I wanted to achieve. However, the following questions came to my mind:

1.) The course instructor decided to leave the attributes' access control level at the default "internal" and not use getters/setters but rather access the attributes directly from outside. Any thoughts on why developers might do that in swift? Is my approach not "swift" enough???

2.) In conclusion: Is there a "swifter" way to implement encapsulation when writing your own class? What are swift's native techniques to achieve the information hiding I am aiming for?

回答1:

You can restrict external property manipulation, by marking the property public for reading and private for writing, as described in the documentation:

class RecordedAudio: NSObject {

    public private(set) let filePathUrl: NSURL!
    public private(set) let title: String?

    init(filePathUrl: NSURL, title: String?) {
        self.filePathUrl = filePathUrl
        self.title = title
    }

}

// in another file

let audio = RecordedAudio(filePathUrl: myUrl, title: myTitle)

let url = audio.filePathUrl // works, returns the url
audio.filePathUrl = newUrl // doesn't compile


回答2:

I do it a bit like in Obj-C:

class MyClass
  private var _something:Int
  var something:Int {
    get {return _something}
// optional: set { _something = newValue }
  }
  init() { _something = 99 }
}

...
let c = MyClass()
let v = c.something

Above is a primitive example, but handled stringent it works as a good pattern.