2016-01-16 1 views
1

J'ai un client qui veut récupérer certaines données basées sur l'effort combiné de deux commandes. La raison pour laquelle j'ai besoin de deux commandes est que la deuxième commande repose sur les données de la première commande. Ma question est quelle est la meilleure façon de passer des données de la première commande à la deuxième commande? J'utilise un objet de coordination qui est un délégué de la première et deuxième commande - mais cela semble désordonné. Est-ce résolvable dans la couche où toutes les commandes sont logées ou a-t-elle besoin de cet objet de coordination?Comment transmettre des données entre des commandes séquentielles?

est ici une représentation de la classe client:

class ViewController: UIViewController, CoordinatorDelegate { 

    // ... 

    @IBAction func didTouchButton(sender: UIButton) { 
     self.coordinator.fetchSchoolID(firtName: "Jane", lastName: "Jones") 
    } 

    // MARK: - CoordinatorDelegate 

    func fetchSchoolIDSucceeded(ID ID: Int) { 
     self.updateUIWithSchoolID(ID) 
    } 

    func fetchSchoolIDFailed(error error: NSError) { 
     self.displayError(error) 
    } 
} 

L'objet coordinateur:

protocol CoordinatorDelegate { 

    func fetchSchoolIDSucceeded(ID ID: Int) 
    func fetchSchoolIDFailed(error error: NSError) 

} 

struct Coordinator: FetchSchoolInfoActionDelegate, FetchStudentInfoActionDelegate { 

    let actionFactory: ActionFactory 
    var delegate: CoordinatorDelegate? 

    func fetchSchoolID(firstName: String, lastName: String) { 

     let firstAction = self.actionFactory.fetchStudentInfoAction(firstName: firstName, lastName: lastName, delegate: self) 

     firstAction.execute() 
    } 

    // MARK: - FetchStudentInfoActionDelegate 

    func fetchStudentInfoSucceeded(studentInfo: StudentInfo) { 

     let secondAction = self.actionFactory.fetchShoolInfoAction(schoolName: studentInfo.schoolName, delegate: self) 

     secondAction.execute() 
    } 

    func fetchStudentInfoFailed(error: NSError) { 
     self.delegate?.fetchSchoolIDFailed(error: error) 
    } 

    // MARK: - FetchSchoolInfoActionDelegate 

    func fetchSchoolIDSucceeded(schoolInfo: SchoolInfo) { 
     self.delegate?.fetchSchoolIDSucceeded(ID: schoolInfo.ID) 
    } 

    func fetchSchoolIDFailed(error: NSError) { 
     self.delegate?.fetchSchoolIDFailed(error: error) 
    } 

} 

Sommairement, le client (ViewController) veut récupérer le schoolID donné un firstName et lastName d'un étudiant . Pour ce faire, deux commandes doivent être exécutées: FetchStudentInfoAction et FetchSchoolInfoAction. La deuxième commande dépend des données de la première commande - dans ce cas, FetchSchoolInfoAction a besoin du schoolName de l'élève qui est récupéré par le FetchStudentInfoAction.

Cela semble désordonné. Si nous imaginons que plus de demandes sont ajoutées à ViewController, l'objet Coordinator deviendra de plus en plus complexe. Existe-t-il une meilleure façon de traiter un ensemble de commandes séquentielles lorsque la deuxième commande nécessite des données du premier? Pourrait-il être géré par un objet sur le calque de commande au lieu de Coordinator?

+0

ce que j'ai actuellement atterri sur la création est une nouvelle commande qui lui-même devient le délégué des deux commandements il est la coordination - et ayant l'objet que j'appelle actuellement 'l'aide Coordinator' juste cette nouvelle acti sur. –

Répondre

0

L'action combinée (fetchSchoolID) indique un graphe d'entité/de relation qui pourrait facilement devenir plus complexe. Je suggère que vous ajoutiez un modèle de gestionnaire d'achèvement pour renvoyer le résultat de vos demandes asynchrones. Par exemple, si la fonction execute() fournit un gestionnaire d'achèvement, vous pourrez obtenir un rappel spécifique dans l'implémentation de fetchSchoolID.

let firstAction = self.actionFactory.fetchStudentInfoAction(firstName: firstName, lastName: lastName, delegate: self) 

    firstAction.execute() 
    { 
     (studentInfo) in 
     let secondAction = self.actionFactory.fetchShoolInfoAction(.... 
     secondAction.execute ... 
    } 

Cela nécessiterait une légère modification de conception dans votre usine d'action (pour stocker et appeler la capture d'achèvement, mais il augmentera considérablement la flexibilité pour combiner et actions enchaînant.

Pour mettre en œuvre ce en vous classe d'action vous pourriez faire quelque chose comme ceci:

class FetchStudent:YourBaseActionClass 
{ 
    var completionHandler:((StudentInfo)->())? = nil 

    // execute allow specification of a completion handler 
    // but doesn't require it 
    override func execute(completion:((StudentInfo)->())? = nil) 
    { 
     completionHandler = completion 
    } 

    // I assume you have something like this in here that 
    // builds the StudentInfo before returning it through the delegate 
    func fetchComplete() 
    { 
     //... your code that prepared the student info 
     completionHandler?(studentInfo) 
    } 

    ... 
+0

pourquoi je l'avais évité en premier lieu, c'est que toutes mes actions se conforment à un protocole ('action') qui les définit comme ayant simplement' execute() '. Je ne veux pas maintenir cela afin que je puisse potentiellement faire différentes opérations avec des collections de 'Action's. voyez-vous des problèmes avec la combinaison des deux dans une nouvelle «action» - par ex. 'FetchSchoolIDAction' - qui utilise lui-même les' FetchStudentInfoAction' et 'FetchSchoolInfoAction' en interne et devient leur délégué? –

+0

Votre délégué doit déjà traiter différentes signatures de fonction en fonction de l'action qui a été déclenchée afin que l'achèvement n'ajoute pas plus de dépendances (il a essentiellement la même signature que la fonction de réussite du délégué).[plus d'informations sur l'action combinée desing dans le commentaire suivant] –

+0

La combinaison des deux actions en une ou en permettant des combinaisons ad-hoc (via des gestionnaires d'achèvement ou autres) est une décision de conception à long terme. Si votre modèle comporte un grand nombre d'entités et qu'il est susceptible de réassembler les cas d'utilisation, il sera plus difficile d'aplatir le plan d'action. D'un autre côté, si vous devez contraindre les combinaisons possibles à un sous-ensemble prédéterminé strict, alors les actions combinées fourniront le meilleur niveau de contrôle. –