0
\$\begingroup\$

Does the following code demonstrate proper use of Strategy design pattern for a simple networking layer in swift 3?

Some code smells I'm unsure about:

  • violates Single responsibiility principle. Each strategy class such as Find, has a method for a different type of implementation. This is because I could want to find an image, or a user, or a chatroom. which are stored at different nodes in Firebase. all these different find methods are clumped together in Find class.

  • At the call sight of a request, if I need to make multiple async request, I nest the next request call inside the closure of the call back. Is this Ok?

  • The request object allows access to every type of insert, and find method. so in my signup VC I could i have the option to download a chatroom. Is even having access to that kind of implementation bad?

I have posted the code below, and left out all the actual implementation for brevity.

Any tips or guidance is much appreciated!

// USE CASE: Would go in viewDidLoad of ViewController
func testMyRequest () {

    let myRequest = Request(insert: Insert(), find: Find())

    myRequest.find?.user(with: "id", handler: { (user) in

        myRequest.find?.nearbyUsers(user: user, handler: { (users) in

            // update collectionView datasource
        })
    })
}

// Is this protocol necessary?
protocol RequestProtocol {
    // - Family of algorithms, related actions.
    var insert: Insert? { get set }
    var find: Find? { get set }
}


// ---------------------------

class Request: RequestProtocol {

    var insert: Insert?
    var find: Find?

    init(insert: Insert?, find: Find?) {
        self.insert = insert
        self.find = find
    }
}


// Use a singleton maybe for the classes below? Why wouldn't I?  

class Insert {

    init() { }

    func user(_ user: User) {
        // insert user to firebase implementation
    }

    func message(_ message: Message) -> Void  {
        // insert message to firebase impelmentation
    }

    func image(data: Data, user: User)  {
        // insert image to firebase impelmentation
    }
}


class Find {

    init() { }

    func user(with id: String, handler: @escaping (_ user: User) -> Void ) {
        // find user implementation
    }

    func allChatrooms(handler: @escaping ([Chatroom]) -> Void) {
        // find all chatrooms implementation
    }

    func nearbyUsers(user: User, handler: @escaping ([User]) -> Void ) {
        // find nearby Users relative to current User location implementation
    }

    // Private helper method
    private func findChatPartners (currentUser: User, chatrooms: [Chatroom] ) -> Set<String> {
    }

}
\$\endgroup\$
  • \$\begingroup\$ Hello friend, SOLID is garbage and you really shouldn't worry about it :) Keep your code DRY and simple, and you will be fine. \$\endgroup\$ – Fluidity Jun 10 '17 at 21:19
1
\$\begingroup\$

What you have is not a Strategy pattern... The key features of the Strategy pattern is that once the Strategy object is inserted into the Context, it is not referenced from outside the Context. Your view controller is still rooting around inside the Context object for the strategy object.

The simplest way to solve this is to have the view controllers be the context. Then you would have a protocol:

protocol API {
    func insert(user: User)
    func insert(message: Message)
    func insert(imageData: Data, toUserID: String)
    func findUser(withID: String, completion: @escaping (User) -> Void)
    // etc...
}

Then you would have a FirebaseAPI that would implement this protocol and a TestAPI that would implement it. The TestAPI would just return canned data so you can test all the possible permutations.

\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy

Not the answer you're looking for? Browse other questions tagged or ask your own question.