I have a base class that stores a lot of other data objects within some data structures, and this class manages those data objects in my collections through a group of add
/remove
functions that keep my data structures in sync.
Now I go to subclass this base class, and the subclass is just like the base class except that it has special rules for what kinds of data objects it will accept (it looks at the values on the data objects, and rejects them if the values aren't right). Because of this "validity" check, I created a new function just for the subclass called change
. In the change
function, it examines all of the incoming data objects and verifies that they are ok, and replaces all of the data objects in the data structures with these data objects.
The problem is that I don't want someone to be able to make a subclass object and allow them to call the base class add
/remove
functions, because I only want the subclass to be able to be changed through the subclass's change
function.
I haven't found a good way to "disable" the use of those base class functions in the subclass. I can override
the functions and implement empty implementations, but there's no feedback to the caller that the function didn't do anything. And if I use something like fatalError
, it isn't compile time, it's runtime.
My other thoughts are to break the functionality of the base class into multiple protocols, and change the base class to simply have all of the data structures, but conforming to none of the protocols and then have multiple subclasses, where one that wants the add
functionality can inherit from the base and additionally conform to the add
protocol, but one that doesn't want add
or remove
can inherit from the base, and simply not conform to any of the protocols and instead create their own change
functions to modify the data structures.
Here's a simpler hierarchy to explain:
class Parent {
func doThis() { print("Parent Did This") }
func doThat() { print("Parent Did That") }
}
class Child: Parent {
override func doThis() {
print("Child Did This")
}
// I want this to be a compile time error
override func doThat() {
print("Not Supported")
return
}
}
Is there an easier way to "hide" a function in a subclass?
To better explain my proposed solution, and whether or not there is an easier way to achieve it with my current hierarchy, here's what the hierarchy would have to look like using some protocols:
protocol CanDoThis {
func doThis()
}
protocol CanDoThat {
func doThat()
}
class Parent {
// Important properties that all children should have
var property1: Int = 0
var property2: String = ""
}
class Child1: Parent, CanDoThis {
func doThis() { print("Child1 Can Do This") }
}
class Child2: Parent, CanDoThat {
func doThat() { print("Child2 Can Do That") }
}
class Child3: Parent, CanDoThis, CanDoThat {
func doThis() { print("Child3 Can Do This") }
func doThat() { print("Child3 Can Do That") }
}
Preventing OverridesYou can prevent a method, property, or subscript from being overridden by marking it as final. Do this by writing the final modifier before the method, property, or subscript's introducer keyword (such as final var , final func , final class func , and final subscript ).
Swift version: 5.6. The override is used when you want to write your own method to replace an existing one in a parent class. It's used commonly when you're working with UIViewControllers , because view controllers already come with lots of methods like viewDidLoad() and viewWillAppear() .
We use the override keyword to declare method overriding. For example, class Vehicle { func displayInfo(){ ... } } class Car: Vehicle { // override method override func displayInfo() { ... } }
The new subclass will inherit all the capabilities of the parent class, but may then be extended to add the missing functionality. Swift extensions provide a useful alternative option to adding functionality to existing classes without the need to create a subclass.
The protocol version would probably be better design - see the Leskov Substitution Principle amount the other things you mentioned.
You can use the attribute @available()
(see Swift -> Language Reference -> Attributes).
class Parent {
func doThis() { print("Parent Did This") }
func doThat() { print("Parent Did That") }
}
class Child: Parent {
override func doThis() {
print("Child Did This")
}
@available(*, unavailable, message:"Child can't doThat")
override func doThat() {
print("Not Supported")
}
}
let parent = Parent()
parent.doThis()
parent.doThat()
let child = Child()
child.doThis()
child.doThat()
You get the following error message on child.doThat()
:
'doThat()' is unavailable: Child can't doThat
However you can get around this by doing the following (again, see Liskov substitution principle):
let maybeChild: Parent = Child()
maybeChild.doThis()
maybeChild.doThat()
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With