Command Pattern example confusion - swift

I am going through the Head-First Design Pattern book when I came across the "Command Pattern" chapter. I have recreated the example in Playground:
protocol RemoteActions {
func turnOn()
}
protocol Product {
var description: String { get set }
}
struct Light: Product {
var description: String
// some other properties
}
struct Heater: Product {
var description: String
// some other properties
}
class LightOn: RemoteActions {
var light: Light
init(light: Light) {
self.light = light
}
func turnOn() {
print("\(light.description) on")
}
}
class HeaterOn: RemoteActions {
var heater: Heater
init(heater: Heater) {
self.heater = heater
}
func turnOn() {
print("\(heater.description) on")
}
}
class Remote {
func doAction(action: RemoteActions) {
action.turnOn()
}
}
let r = Remote()
let l = Light(description: "light1")
let h = Heater(description: "heater1")
let lo = LightOn(light: l)
let ho = HeaterOn(heater: h)
r.doAction(action: lo)
r.doAction(action: ho)
I mean what are the benefits of this pattern?? Yes, I can see that the remote will only know about its actions, but what if I wanted to create a new Product to be turned on and off? I will undoubtfully have to create a new "Command Class" right? Which makes this part in the book really silly:
Wouldn't it be better if we conformed the action into said Product? Like this:
protocol RemoteActions {
func turnOn()
}
protocol Product: RemoteActions {
var description: String { get set }
func turnOn()
}
struct Light: Product {
var description: String
// some other properties
func turnOn() {
print("\(description) on")
}
}
struct Heater: Product {
var description: String
// some other properties
func turnOn() {
print("\(description) on")
}
}
class Remote {
func doAction(product: Product) {
product.turnOn()
}
}
let r = Remote()
let l = Light(description: "light1")
let h = Heater(description: "heater1")
r.doAction(product: l)
r.doAction(product: h)

gof says: 'The Command pattern lets toolkit objects make requests of unspecified application objects by turning the request itself into an object. This object can be stored and passed around like other objects. The key to this pattern is an abstract Command class, which declares an interface for executing operations. In the simplest form this interface includes an abstract Execute operation. Concrete Command subclasses specify a receiver-action pair by storing the receiver as an instance variable and by implementing Execute to invoke the request. The receiver has the knowledge required to carry out the request.'

Related

How to conform to a protocol with a generic superscript affordance in Swift?

TL;DR
How can I conform to the supscript function of a protocol in my implementation?
Protocol:
protocol DataStore {
//...
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
}
Neither
subscript<T>(id: T.ID) -> T where T : Identifiable {
get { Project() }//just to return anything for the time being…
set {}
}
nor
subscript(id: Task.ID) -> Task {
get { Project() }//just to return anything for the time being…
set {}
}
work...
The details:
I have developed a habit of creating specific data stores for my models. They all have the same functionality. A specific example could look like this:
final class ProjectDataStore: ObservableObject {
{
static let shared = ProjectDataStore()
let persistence = AtPersistLocally.shared // that's from a personal package I made that handles saving and loading locally as json files
#Published var projects: [Project] {
didSet { //save }
}
private init(projects: [Project]? = nil) {
//load from persistence
}
subscript(id: Project.ID) -> Project? {
get { //return project with id }
set { //set project at id }
}
func getBinding(by id: Project.ID) -> Binding<Project> {
//return Binding
}
func getProjectBy(taskId: Task.ID) -> Project {
//return instance
}
private func getIndex(by id: Project.ID) -> Int? {
//return index in array
}
private func load() -> [Project] {
//load from persistence
}
private func save() {
//save from persistence
}
}
While this works as expected, I'd like to be able to introduce a protocol that I could when adding new functionality / models to have a blueprint on what's necessary for my DataStore.
Here is my first attempt:
protocol DataStore {
static var shared: Self { get }
}
extension DataStore {
var persistence: AtPersistLocally {
get {
AtPersistLocally.shared
}
}
}
To also conform to ObservableObject, I introduce a typealias
typealias ObservableObjectDataStore = DataStore & ObservableObject
and change my model to conform to this new typealias:
final class ProjectDataStore: ObservableObjectDataStore {
//...
}
With this, I already have a static instance and access to persistence available.
Next step of course is to move more and more properties to the protocol–which is what I am struggling with right now.
Let's look at superscript first of all: I guess I understand what needs to be added to the protocol:
protocol DataStore {
//...
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
}
My problem now is that I don't know how to go about conforming to this subscript now while also getting access to a concrete model from the generic T from the implementation. This attempt…
final class ProjectDataStore: ObservableObjectDataStore {
//...
subscript<T>(id: T.ID) -> T where T : Identifiable {
get { Project() }//just to return anything for the time being…
set {}
}
}
…leads to the error message Cannot convert return expression of type 'Task' to return type 'T'.
If I go with…
final class ProjectDataStore: ObservableObjectDataStore {
//...
subscript(id: Task.ID) -> Task {
get { Project() }//just to return anything for the time being…
set {}
}
}
…the error message changes to Type 'TaskDataStore' does not conform to protocol 'DataStore'.
So I guess basically what I am asking is: how can I conform to my protocol's generic superscript in my implementation of ProjectDataStore?
I have a feeling that I am not too far of, but a critical info is obviously missing…
subscript<T>(id: T.ID) -> T where T: Identifiable { get set }
This says that the caller may pick any Identifiable T, and this method promise return a value of that type. This can't be implemented (other than calling fatalError() and crashing). Identifiable doesn't even promise that the type has an init. Your protocol is impossible.
What you probably meant to write is, which says that a given DataStore will return some specific Identifiable type (not "whatever type the caller requests"):
protocol DataStore {
associatedType Item: Identifiable
subscript(id: Item.ID) -> Item { get set }
}
But I expect this would be much better implemented without a protocol, and just use a generic struct:
struct DataStore<Item: Identifiable> { ... }

Protocol Conformance Check

How can I perform conformance check against protocol with AssociatedType. Xcode shows error:
Protocol 'MyListener' can only be used as a generic constraint because
it has Self or associated type requirements
My ultimate goal is to extract "MyListener.section" from an array of weakObjects, where the handler matches the function argument.
Note. The NSPointerArray of weakObjects is suppose to capture different types of MyListeners.
public class MyHandler<O,E> {
var source = [O]()
var dest = [E]()
}
public protocol MyListener:class {
var section: Int {get}
associatedtype O
associatedtype E
var handler: MyHandler<O,E>? { get }
}
public class MyAnnouncer {
private let mapWeakObjects: NSPointerArray = NSPointerArray.weakObjects()
public func add<L: MyListener>(listener: L) {
let pointer = Unmanaged.passUnretained(listener).toOpaque()
mapWeakObjects.addPointer(pointer)
}
public func search<O, E> (h:MyHandler<O,E>) -> [Int] {
_ = mapWeakObjects.allObjects.filter { listener in
if listener is MyListener { // Compilation failed
}
if let _ = listener as? MyListener { //Compilation error
}
if listener is MyListener.Type { //Compilation failed
}
}
return [] // ultimate goal is to extract corresponding [MyListener.section].
}
}
Unfortunately, Swift doesn't support protocols with AssociatedType to conformance.
You should try to use Type Erasure. One of the way is to implement type erasure by creating new AnyType class.
Here is another way to release type erasure (example from the internet)
protocol SpecialValue { /* some code*/ }
protocol TypeErasedSpecialController {
var typeErasedCurrentValue: SpecialValue? { get }
}
protocol SpecialController : TypeErasedSpecialController {
associatedtype SpecialValueType : SpecialValue
var currentValue: SpecialValueType? { get }
}
extension SpecialController {
var typeErasedCurrentValue: SpecialValue? { return currentValue }
}
extension String : SpecialValue {}
struct S : SpecialController {
var currentValue: String?
}
var x: Any = S(currentValue: "Hello World!")
if let sc = x as? TypeErasedSpecialController { // Now we can perform conformance
print(sc.typeErasedCurrentValue)
}

Swift Protocol Extension - Can't Access Func

If I have a series of protocols like so:
protocol Customer {
var name:String { get set }
var age: Int { get set }
var startDate:Date { get set }
var meals:Array<String> { get set }
var market:Int { get set }
}
protocol Vegan:Customer {
}
protocol Vegetarian:Customer {
}
protocol Paleo:Customer {
}
and extension like so:
extension Customer where Self:Vegan, Self:Vegetarian {
func getMeals() -> Array<String> {
return ["VeganMeal1", "VeganMeal2", "VeganMeal3", "VeganMeal4"]
}
}
extension Customer where Self:Vegetarian {
func getMeals() -> Array<String> {
return ["VegetarianMeal1", "VegetarianMeal2", "VegetarianMeal3", "VegetarianMeal4"]
}
}
extension Customer where Self:Paleo {
func getMeals() -> Array<String> {
return ["PaleoMeal1", "PaleoMeal2", "PaleoMeal3", "PaleoMeal4"]
}
}
and this struct
struct aCustomer:Customer, Vegan {
var name:String
var age: Int
var startDate:Date
var meals:Array<String>
var market:Int
}
when I create a new object based on that struct
var newCustomer = aCustomer(name:"William", age:40, startDate:Date(), meals:[], market:1)
how come I can't access the getMeals function in the extensions? I get an error stating getMeals is an ambiguous reference.
extension Customer where Self:Vegan, Self:Vegetarian {
extends Customer in the case where the adopter or Customer also both adopts Vegan and Vegetarian. Your aCustomer (a struct type starting with a small letter?? the horror, the horror) does not do that, so the extension doesn't apply to it.
If the goal is to inject the same code either when the adopter adopts Vegan or when the adopter adopts Vegetarian, use two extensions, or, if you don't like the repetition, have them both adopt some "higher" protocol that is extended with the desired code to be injected.

Swift 3 generic function ambiguous return

I need a single function to resolve different dependencies in a class.
But there is a compilation error appears.
Is it possible to create that generic function or there are some compiler constraints in Swift?
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
return resolve() as T
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
EDIT: This question is not about if Swift allows to create two functions that differs only by return type. I know it's possible. I think there are some artificial constraints in the compiler but not in the fundamental logic that should allow to infer needed type from a context.
Let's put yourself into the compiler's shoes. Imagine that this was not causing an error and you had one signature with different outputs.
Whenever you call resolveDependency<T>() -> T, the compiler will return you a type T which is an instance conforming to a protocol in your case.
In your code you call this method with different instances conforming to the same protocol. At that stage the compiler has no idea about this. All it knows is that you have passed an instance of T and it needs to give you a result in shape of T
There is no problem until this point. As soon as you execute
return resolve() as! T
The compiler will be confused. I have a T but I don't know which resolve() I will call... All I know is that I have a T. How would I know if this is an Order or a Client ?
In order to prevent such confusions we have compiler-time errors. At least this is the case for Swift. (I don't know how this works in other languages)
You need to define different methods with different signatures and cast your type accordingly to get a similar result
fileprivate func resolveDependency<T>() -> T {
// check if this is an Order
resolveForOrder()
// check if this is a Client
resolveForClient()
}
private func resolveForOrder() -> Order {
return LastOrder()
}
private func resolveForClient() -> Client {
return ImportantPerson()
}
This is like trying to fix a space shuttle engine with a car mechanic. Yes, they both have an engine, they both run on fuel but the mechanic only knows how to fix your car's engine he is not a rocket scientist(!)
This code works fine:
import Foundation
protocol Client: class {
var description: String { get }
}
final class ImportantPerson : Client {
var description: String {
return "Important person"
}
}
protocol Order: class {
var description: String { get }
}
final class LastOrder : Order {
var description: String {
return "Last order"
}
}
final class A {
fileprivate func resolveDependency<T>() -> T {
if T.self == Client.self {
return resolve() as Client as! T
} else {
return resolve() as Order as! T
}
}
private func resolve() -> Client {
return ImportantPerson()
}
private func resolve() -> Order {
return LastOrder()
}
}
let a = A()
let client: Client = a.resolveDependency()
let order: Order = a.resolveDependency()
print("Client: \(client.description)")
print("Order: \(order.description)")
But I believe that compiler should resolve the if else clause himself, it's not so hard as I suppose.
Also there is some bug in the compiler when it tries to match types like that:
switch T.self {
case is Client:
return resolve() as Client as! T
default:
return resolve() as Order as! T
}

Is it possible to convert instance of a class to an instance of a subclass?

I've recently came across a case where it would be very convenient to convert an instance of a class to a subclass, while the instance has been created within the parent class. But I've never seen such thing. So is there a way to do something like:
class Foo {
var name: String
}
class Bar: Foo {
var friendName: String
}
let foo = Foo(name: "Alice")
foo.toBar(friendName: "Bob")
// foo now of type Bar, as if I'd done
// foo = Bar(name: "Alice", friendName: "Bob")
If that's not possible, is there some reasons this would be impossible from a design perspective?
===edit=== description of a use case where it could make sense
Let say there's two views representing what correspond to the same database record for a book, on is a just a preview of the book and another is a more complex view. Models could be:
protocol BookMetaDelegate {
func onReadStatusUpdate()
}
/// describe a book
class BookMeta {
var delegate: BookMetaDelegate?
private var _hasBeenRead: Bool
var hasBeenRead: Bool {
get {
return _hasBeenRead
}
set {
guard newValue != _hasBeenRead else { return }
_hasBeenRead = newValue
delegate?.onReadStatusUpdate()
}
}
var title: String
}
/// contains all the content of a book
class Book: BookMeta {
var content: BookContent
var lastPageRead: Int
/// some logic that only makes sense in a Book instance
func getLastPageRead() {
return content.getPage(lastPageRead)
}
}
and views could look like:
class BookPreview: UIView, BookMetaDelegate {
var book: BookMeta
init(book: BookMeta) {
book.delegate = self
}
func onReadStatusUpdate() {
print("read status has changed! UI should update")
}
}
class BookView: UIView {
var book: Book
init(book: Book) {
book.hasBeenRead = true
}
}
Then things could happen like
fetch(bookMetaWithId: 123).then { bookMeta in // bookMeta is of type BookMeta
let preview = BookPreview(book: bookMeta)
...
fetch(contentOf: bookMeta).then { content, lastPageRead in
bookMeta.asBook(content: content, lastPageRead: lastPageRead)
let bookView = BookView(book: bookMeta) // doing so will change the hasBeenRead flag and message the instance's delegate, ie the preview
...
}
}
Thinking more about it, it sounds like that if such thing was possible, it'd break things like:
class Foo {
var name: String
}
class Bar: Foo {
var friendName: String
}
class Bla: Foo {
var surname: String
}
func something(foo: Foo) {
foo.toBla(surname: "Will")
}
let bar = Bar(name: "Alice", friendName: "Bob")
something(foo: bar) // what does that do ??? is bar a Bla now ?
so that'd be a good reason for making such casting impossible.