Is there any core difference between Liskov Substitution Principle (LSP) and Interface Segregation Principle (ISP)? Ultimately, both are vouching for designing the interface with common functionalities and introduce a new interface when you have special purpose of functionalities.
LSP: The subtype must honor the contracts it promises.
ISP: The caller shouldn't depend on more of the base type's interface than it needs.
Where they fit: If you apply the ISP, you use only a slice of the receiver's full interface. But according to LSP, the receiver must still honor that slice.
If you fail to apply ISP, there can be a temptation to violate LSP. Because "this method doesn't matter, it won't actually be called."
Both of them are SOLID principles
LSP (Liskov Substitution): this principle asks you to make sure that all child classes have the same behavior as the parent class.
for example: if you have a Device class and it has function callBaba() which get your father phone number then calls him, So you must make sure that the callBaba() method in all subclasses of the Device does the same job. if any of the subclasses of Device have another behavior inside callBaba() this is mean you broke the LSP
Example of code that breaks Liskov Principle.
class Device {
func callBaba() {
print("I will find your father and I will call him")
}
}
class Calculator: Device {
override func callBaba() {
print("Sorry, I don't have this functionality ")
}
}
The Solution
interface CanCall {
func callBaba()
}
class Device {
// all basic shared functions here.
}
class Calculator: Device {
// all functions that calculator can do + Device
}
class SmartPhone: Device implements CanCall {
// all smartphone stuff
func callBaba() {
print("I will find your father and I will call him")
}
}
ISP (Interface Segregation): Asks you to create a different interface for different responsibilities, in other words, don't group unrelated behavior in one interface,
You break ISP if
You have already an interface with many responsibilities, and the implementor doesn't need all this stuff
this breaks ISP principle because it has two different
responsibilities
protocol Animal {
func fly()
func eat()
}
The Solution
protocol Flyable {
func fly()
}
protocol Feedable {
func eat()
}
The LSP governs relationships between parent and child classes (i.e. hierarchical relationships). It tells you how to implement an API.
The ISP governs relationships between parent and client classes (i.e. producer/consumer relationships). It tells you when to implement an API.
Consider an interface with a hundred methods. A child class could implement all hundred without violating the contracts defined by any of them, and thus satisfying Liskov Substitution; but it's hard to imagine every client would need all of those methods, so Interface Segregation is almost sure to be violated.
Conversely, an interface with only one method surely satisfies Interface Segregation; but if an implementation doesn't obey that one method contract, then Liskov Substitution is violated.
See also: LSP vs DIP
Related
I understand that generally I cannot instantiate a protocol.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
My code is as below and line:
protocol Solution {
var answer: String { get }
}
protocol Problem {
var pose: String { get }
}
protocol SolvableProblem: Problem {
func solve() -> Solution?
}
protocol ProblemGenerator {
func next() -> SolvableProblem
}
protocol Puzzle {
var problem: Problem { get }
var solution: Solution { get }
init(problem: Problem, solution: Solution)
}
protocol PuzzleGenerator {
func next() -> Puzzle
}
protocol FindBySolvePuzzleGenerator: PuzzleGenerator {
var problemGenerator: ProblemGenerator { get }
}
extension FindBySolvePuzzleGenerator {
func next() -> Puzzle {
while true {
let problem = problemGenerator.next()
if let solution = problem.solve() {
return Puzzle(problem: problem, solution: solution)
}
}
}
}
The line:
return Puzzle(problem: problem, solution: solution)
gives error: Protocol type 'Puzzle' cannot be instantiated
Imagine protocols are adjectives. Movable says you can move it, Red says it has color = "red"... but they don't say what it is. You need a noun. A Red, Movable Car. You can instantiate a Car, even when low on details. You cannot instantiate a Red.
But if I include an initialiser in the protocol then surely the compiler knows that when the protocol is used by a struct or class later, it will have an init which it can use?
Protocols must be adopted by classes, and there might be a dozen different classes that all adopt your Puzzle protocol. The compiler has no idea which of those classes to instantiate.
Protocols give us the power to compose interfaces without the complexity of multiple inheritance. In a multiple inheritance language like C++, you have to deal with the fact that a single class D might inherit from two other classes, B and C, and those two classes might happen to have methods or instance variables with the same name. If they both have a methodA(), and B::methodA() and C::methodA() are different, which one do you use when someone call's D's inherited methodA()? Worse, what if B and C are both derived from a common base class A? Protocols avoid a lot of that by not being directly instantiable, while still providing the interface polymorphism that makes multiple inheritance attractive.
I understand that I can't do it - I just want to understand why the
compiler can't do it?
Because protocols in Swift represent abstraction mechanism. When it comes to abstraction, you could think about it as a template, we don't have to care about the details of how it behaves or what's its properties; Thus it makes no sense to be able to create an object from it.
As a real world example, consider that I just said "Table" (as an abstracted level), I would be pretty sure that you would understand what I am talking about! nevertheless we are not mentioning details about it (such as its material or how many legs it has...); At some point if I said "create a table for me" (instantiate an object) you have the ask me about specs! and that's why the complier won't let you create object directly from a protocol. That's the point of making things to be abstracted.
Also, checking: Why can't an object of abstract class be created? might be helpful.
Unfortunately swift does not allow that even with such "hack"
You would need to use a class that confirms to that protocol as an object you refer to.
When you instantiate an object, the Operating System has to know how to allocate and deal with that kind of object in the memory: Is it a reference type (Classes)? Strong, weak or unowned reference? Or is it a value type (Structs, Strings, Int, etc)?
Reference types are stored in the Heap, while value types live in the Stack. Here is a thorough explanation of the difference between the two.
Only Reference and Value types (objects) can be instantiated. So, only the objects that conform to that protocol can then be instantiated, not the protocol itself. A protocol is not an object, it is a general description or schema of a certain behavior of objects.
As to Initialization, here what the Apple docs say:
Initialization is the process of preparing an instance of a class,
structure, or enumeration for use. This process involves setting an
initial value for each stored property on that instance and performing
any other setup or initialization that is required before the new
instance is ready for use.
I'm faced with a situation where I am defining a reusable base class in a module, and I want to provide certain functions that should be callable only by subclasses, not external users of that subclass.
I'm writing a framework and packaging it as a Swift module. Part of my framework includes a base class that can be subclassed to add functionality, but whereby the derived class also has a further external purpose as well. Imagine defining a new kind of view: it derives from UIView or NSView, then provides additional logic, and is then itself instantiated by another party.
In this case, I'm the one defining the UIView-like class that is intended to be subclassed, and along with it comes a lot of private UIView internal stuff, like measurement, arranging, who knows, internal stuff.
The point is, end users of this new view class don't want to see the internals of the architecture that supported the subclassing, those should be completely inside the black box of what the subclass represents.
And it strikes me that this is now impossible in Swift.
I really don't understand why Swift got rid of protected access control. According to Apple, the function that I want to expose only to subclasses "isn't really useful outside the subclass, so protection isn’t critical".
Am I missing something? Is this a whole class of design patterns that Swift simply cannot support?
One thought that occurs to me is I could perhaps split up the public-public and the private-public parts of my class into two parts, perhaps using protocols, whereby public-public users would only see the public protocol and "private" public users would see the "private" protocol as well. Alas this seems like a lot of engineering for something that used to be free.
FWIW — I've been continually asking for better access control in Swift (including protected) since before there was access control in Swift. Now, 3.5 years after we were told to give the Swift approach to access control a try, Swift has been my primary language for almost 3 of those years and I still think the access control paradigm is clumsy and unable to model concepts that are easy in almost all similar languages.
The largest mitigating factor for me is that Swift has steered me away from ever using inheritance and subclassing 95% of the time, which I think is a good thing. So this issue comes up less than it may have otherwise. But for situations exactly as you are describing, there isn't an equivalent way to accomplish what you are doing using only protocols and protocol extensions, so you are stuck either polluting a public API with possibly harmful internal details, or using some workaround (like the one that follows) which has the smallest possible public API exposure, and simulates what you want at the cost of boilerplate and awkwardness.
That said, the approach I take is somewhat inspired by Objective C, where there is also no real protected access control, but the convention is to declare a public API header (which client code will import and reference) and a special "+Subclassing" header which only subclasses will import in their implementation, giving them visibility into the not-for-public-consumption internals.
In Swift, this isn't directly possible either, but given a class like this:
open class SomeClass {
private var foo: String
private var bar: Data
public init(){
foo = "foo"
bar = Data()
}
private func doInternalThing() {
print(foo)
}
}
You can add a nested "Protected" wrapper via extension (has to be in the same file as your class declaration), which takes an instance of the class (or a subclass) and exposes the protected-level internals as a sort of proxy:
// Create a nested "Protected" type, which can accept an instance of SomeClass (or one of its subclasses) and expose the internal / protected members on it
public extension SomeClass {
public class Protected {
unowned private var someClass: SomeClass
public var foo: String {
get {
return someClass.foo
}
set {
someClass.foo = newValue
}
}
public init(_ someClass: SomeClass) {
self.someClass = someClass
}
public func doInternalThing() {
someClass.doInternalThing()
}
}
}
Outside of the framework, in the client application, the protected members are accessed in a subclass like this:
class SomeSubclass: SomeClass {
private lazy var protected: SomeClass.Protected = { SomeClass.Protected(self) }()
func doSomething() {
protected.foo = "newFoo" // Accesses the protected property foo and sets a new value "newFoo"
protected.doInternalThing() // Prints "newFoo" by calling the protected method doInternalThing which prints the foo property.
}
}
There are pros and cons for this approach. The cons are mainly the amount of boilerplate you need to write to map all your properties and functions from the Protected wrapper to the actual class instance as shown above. Also, there is no avoiding the fact that consumers will see SomeClass.Protected as a publicly visible type, but hopefully it's clear that it shouldn't be used and it's difficult enough to use it arbitrarily that it won't happen.
The pros are that there isn't a lot of boilerplate or pain for clients when creating subclasses, and its easy to declare a lazy "protected" var to get the desired API. It's pretty unlikely that non-subclass would stumble upon or use this API accidentally or unwittingly, and it's mostly hidden as desired. Instances of SomeSubclass will not show any extra protected API in code completion or to outside code at all.
I encourage anyone else who thinks access control — or really in this case, API visibility and organization — to be easier than it is in Swift today to let the Swift team know via the Swift forums, Twitter, or bugs.swift.org.
You can kinda, sorta work around it by separating out the for-subclasses stuff into a separate protocol, like this:
class Widget {
protocol SubclassStuff {
func foo()
func bar()
func baz()
}
func makeSubclassStuff() -> SubclassStuff {
// provide some kind of defaults, or throw a fatalError if this is
// an abstract superclass
}
private lazy var subclassStuff: SubclassStuff = {
return self.makeSubclassStuff()
}()
}
Then you can at least group the stuff that's not to be called in one place, to avoid it polluting the public interface any more than absolutely necessary and getting called by accident.
You can also reconsider whether you really need the subclass pattern here, and consider using a protocol instead. Unfortunately, since protocols can't nest types yet, this involves giving the subclass-specific protocol an Objective-C-style prefixed name:
protocol WidgetConcreteTypeStuff {
...
}
protocol Widget {
var concreteTypeStuff: WidgetConcreteTypeStuff { get }
}
It seems reasonable to use UML Interfaces to visualize Swift Protocols in UML. But how should I visualize an extension that provides a default implementation for a specific protocol? Should I just use a class like <<extension>>ProtocolName that inherits from that protocol?
An extension exists in the scope of a certain class and just adds some functionality to it. So I would represent the extension as subclass (eventually packaging might be preferred). To show that it's an extension I would use a stereotype. The dependency on the class which is extended is somewhat optional since in the context it is a naming convention.
If the extension will additionally adhere to some protocol you just add realization relations to the according interface classes.
This is one way to express this. Since there is no native UML construct for an extension you are relatively free to invent you own idiom here.
In short
A Swift protocol is in principle an UML interface: a class does not inherit anything from an interface/protocol, but must implement the feature that the interface/protocol promises.
Protocol extensions change this semantic equivalence: a protocol extension can provide features that the conformant classes would inherit. This is incompatible with an UML interface and corresponds to the semantic of an abstract class. But using abstract classes would make it confusing in regard to multiple inheritance. A stereotype «protocol» would seem preferable.
More explanations
Protocols
A swift protocol that is not extended corresponds indeed to an UML interface, despite slight differences in the wording:
Swift: A protocol defines a blueprint of methods, properties, and other requirements that suit a particular task or piece of functionality. The protocol can then be adopted by a class, structure, or enumeration to provide an actual implementation of those requirements.
vs:
UML: An Interface is a kind of Classifier that represents a declaration of a set of public Features and obligations that together constitute a coherent service. An Interface specifies a contract; any instance of a Classifier that realizes the Interface shall fulfill that contract.
Class extensions
There are different kind of extensions. A class extension adds features to the classes that they extend. If the extension occurs in the same file, it even has access to the private members of the class.
class MyClass {
func hello()->Void { print ("Hello, World !"); }
}
var c = MyClass()
extension MyClass { // first extension
func hellobye() -> Void { hello(); print(" Good bye!"); }
}
extension MyClass { // second extension
func bye() -> Void { print("Au revoir!"); }
}
c.hello() // the object has all the features of class + extension
c.hellobye() // even if it was defined befor the extension
c.bye()
The extension does not have a distinct name: it just redefines the original type, and the class behaves as if the initial definition and extensions would be the same classifier, just split up in the source code:
If the extensions and the initial class are defined in the same package, the cleanest way to represent it in UML would be to enrich the initial class, in the UML diagram.
If the extensions are defined in another package you could represent the full set of extensions to the same class as an own class, and a merge package to combine both. Since the original class is required for the extension to work you could in addition show a dependency between the two. Alternatively you could also think of an «class extension» stereotype. But again, grouping all the extensions to the same class in the package, because of the UML unique naming constraint.
Protocol extensions
Protocol extensions change the nature of the underlying protocol. While the original protocol was an interface without any implementation, the extended protocol will provide some implementations:
protocol MyProto {
var v1:String { get }
func op1() -> Void
func op2() -> Void
}
class Test : MyProto {
var v1:String = "abc"
func op1() -> Void { print("Op 1"); }
func op2() -> Void { print("Op 2"); }
}
extension MyProto {
var dev1:String { get { return "de"+v1; }}
func combo() -> Void { op1(); op2(); print("Combo 1 and 2"); }
}
var test = Test()
test.combo()
print (test.dev1);
In UML, the extended protocol would correspond to an «abstract» class, i.e a class that cannot be directly instantiated because of some missing features, but which may have some features well defined that are inherited. This situation is not fully supported in UML, since there is no modelling way to transform an interface into an abstract class:
The cleanest way would then be to use an UML profile that defines the stereotype «protocol» as a special form of «abstract» classes. The protocol extensions would then be dealt with as explained above for the classes, using a «protocol extension» in the situation where a «class extension» was mentioned.
I have few questions for Swift developers regarding the concept of abstract classes.
How do you define an abstract class in Swift? Is there any way to prevent a class from being instantiated, while providing an initializer for its subclasses to use?
How do you define abstract methods, while implementing others? When defining abstract methods, Apple generally points you to protocols (interfaces). But they only solve the first part of my question, since all of the methods they define are abstract. What do you do when you want to have both abstract and non-abstract methods in your class?
What about generics? You might have thought about using protocols together with extensions (categories). But then there is an issue with generics because protocols can't have generic types, only typealiases.
I have done my homework and I know about solving these issues using methods, such as fatalError() or preconditionFailure() in the superclass and then overriding them in a base class. But that seems like ugly object design to me.
The reason I'm posting this is to find out whether there exists more general and universal solution.
Thanks in advance,
Petr.
As of today (April 7, 2016), the proposal to introduce abstract classes and methods to Swift (SE-0026) has been deferred.
Joe Groff posted the following in swift-evolution-announce on March 7, 2016:
The proposal has been deferred from Swift 3. Discussion centered around whether abstract classes fit in the direction of Swift as a "protocol-oriented" language. Beyond any religious dogmas, Swift intends to be a pragmatic language that lets users get work done. The fact of the matter today is that one of Swift's primary target platforms is the inheritance-heavy Cocoa framework, and that Swift 2's protocols fall short of abstract classes in several respects [...].
We'd like to revisit this feature once the core goals of Swift 3 have been addressed, so we can more accurately consider its value in the context of a more complete generics implementation, and so we can address the finer points of its design.
I encourage you to read the full email, but I think the conclusion is the same as what you came up with in your question: we're currently stuck with the Objective-C way of doing things (raising exceptions).
There is no Abstract concept in Swift. But we can achieve that scenario by using Inheritance concept like the code below:
class ParentVC:UIViewController {
func loadInformation() {
}
}
class ChildVC:ParentVC {
// This is an Abstract Method
override func loadInformation() {
}
}
How do you define abstract methods, while implementing others?
The "swifty" way of achieving this is combining protocols and extensions, sometimes also typealiases. For data, you are going to define abstract properties in your protocol, then re-define them in a concrete class, then unite all that using a typealias and the & operator:
protocol BaseAbstract: class {
var data: String { get set }
func abstractMethod()
func concreteMethod()
}
extension BaseAbstract {
// Define your concrete methods that use the abstract part of the protocol, e.g.:
func concreteMethod() {
if !data.isEmpty {
abstractMethod()
}
}
}
class BaseImpl {
// This is required since we can't define properties in extensions.
// Therefore, we define a class with a concrete property and then
// unite it with the protocol above in the typealias below.
var data: String = "Hello, concrete!"
}
typealias Base = BaseAbstract & BaseImpl // et voila, `Base` is now ready to be subclassed
class Subclass: Base {
func abstractMethod() { // enforced by the compiler
}
}
(It can get tricker if you have generics in this scenario. Currently trying to figure it out.)
Suppose that I have to implement two different interfaces declared in two different packages (in two different separated projects).
I have in the package A
package A
type interface Doer {
Do() string
}
func FuncA(Doer doer) {
// Do some logic here using doer.Do() result
// The Doer interface that doer should implement,
// is the A.Doer
}
And in package B
package B
type interface Doer {
Do() string
}
function FuncB(Doer doer) {
// some logic using doer.Do() result
// The Doer interface that doer should implement,
// is the B.Doer
}
In my main package
package main
import (
"path/to/A"
"path/to/B"
)
type C int
// this method implement both A.Doer and B.Doer but
// the implementation of Do here is the one required by A !
func (c C) Do() string {
return "C now Imppement both A and B"
}
func main() {
c := C(0)
A.FuncA(c)
B.FuncB(c) // the logic implemented by C.Do method will causes a bug here !
}
How to deal with this situation ?
As the FAQ mentions
Experience with other languages told us that having a variety of methods with the same name but different signatures was occasionally useful but that it could also be confusing and fragile in practice.
Matching only by name and requiring consistency in the types was a major simplifying decision in Go's type system.
In your case, you would satisfy both interfaces.
You can you the can test whether an object (of an interface type) satisfies another interface type A.Doer, by doing:
if _, ok := obj.(A.Doer); ok {
}
The OP adds:
But the logic implemented in the Do method to satisfy A is completely different from the one in B.
Then you need to implement a wrapper around you object:
a DoerA, which has your object C as a field, and implement A.Do() in a manner that satisfy how A.Do()is supposed to work
a DoerB, which has your same object C as a field, and implement B.Do() in a manner that satisfy how B.Do() is supposed to work
That way, you will know which Doer to pass to a function expecting an A.Doer or a B.Doer.
You won't have to implement a Do() method on your original object C, which would be unable to cope with the different logic of A.Do() and B.Do().
By definition, you are satisfying both:
A Go type satisfies an interface by implementing the methods of that interface, nothing more. This property allows interfaces to be defined and used without having to modify existing code. It enables a kind of structural typing that promotes separation of concerns and improves code re-use, and makes it easier to build on patterns that emerge as the code develops. The semantics of interfaces is one of the main reasons for Go's nimble, lightweight feel.
So, with that in mind, you can either:
a) Add comments to the the interface methods defining your expectations on the logic (see the io.Reader interface or a good example)
b) Add an extra method called ImplementsDoerA and ImplementsDoerB on the interfaces (also mentioned in the FAQ).