2015-07-28 1 views
1

J'ai différentes commandes qui partagent toutes des données communes, donc j'ai extrait cela à un super classe Command. Toutes les commandes concrètes fonctionnent sur un objet de Foo lorsqu'elles implémentent la méthode execute. L'appelant réel de la commande est un client TheClient qui crée un nouvel objet de la commande requise et l'exécute directement.Mise en œuvre de modèle de commande ou d'adaptation

Je l'ai implémenté de telle sorte que le client et inovker est indépendant des détails d'implémentation dans les commandes, et plus important encore, indépendant de la classe Foo.

je les questions suivantes:

1) Est-ce une mise en œuvre du schéma de commande, ou en quelque sorte l'adoption de celui-ci?

2) D'après ma compréhension du modèle de commande, dans cet exemple Foo est le récepteur. Est-ce correct?

3) Contrairement au modèle de commande pure, j'ai fusionné l'invocateur et le client dans la même classe. Certaines personnes disent que cela est OK dans le modèle de commande, puisque les deux sont une construction théorique et dans une implémentation réelle, ils peuvent être dans la même classe. Est-ce correct?

public abstract class Command { 
    protected String a; 
    protected Foo foo; 
    public Command(String a) { 
    this.a = a; 
    this.foo = new Foo(a); 
    } 
    public abstract void execute(); 
} 

public class StartCommand extends Command { 
    private String b; 
    public StartCommand(String a, String b) { 
    super(a); 
    this.b = b; 
    } 
    public void execute() { 
    this.foo.doSomething("start " + a + " with " + b); 
    } 
} 

// ... other commands ... 

public class Foo { 
    protected String name; 
    public Foo(String name) { 
    this.name = name; 
    } 
    public void doSomething(String action) { 
    // does something... 
    } 
} 

public class TheClient { 
    public static void main(String[] args) { 
    Command command = new StartCommand("x", "y"); 
    command.execute(); 
    } 
} 

Répondre

1

1ère question: Oui. C'est une adaptation du modèle de commande.

2e question: Foo est le destinataire.

3e question: Oui, l'invocateur est fusionné avec la classe client. Voici un petit problème. Le Foo n'est pas indépendant du béton StartCommand. Il est vrai, que vous devez modifier la classe Command à la fois l'implémentation, quand un renommage se produit sur la classe Foo par exemple, mais l'instanciation du Foo devrait être quelque part dans le main si vous demandez à Oncle Bob. Dans votre exemple, il se trouve dans le constructeur Command.

EDIT

Vous pouvez instancier Foo dans un autre endroit, que l'enrouler autour de la ConcreteCommand. Than Invoker va latch autour de la commande. Les deux enveloppes engloberont le découplage et la responsabilité unique. Par exemple, vous pouvez tester tous les comportements de Foo sans avoir peur des effets secondaires de la commande. Dans le test Vous créez un Foo, essayez-le, pas de surprise. Test du StartCommand Vous devez vérifier si un chaînage de méthode a lieu. Comme ceci:

public Command.SetAOfFoo(string a) { 
    this.foo.SetA(a); 
} 

Vous devez vérifier toutes les propriétés de Foo à tenir, que vous êtes arrivé la première fois avec les tests unitaires de Foo. Vous trouverez des tests de test défaillants car certains appels au StartCommand ont modifié l'état de Foo, ce qui a entraîné des tests défaillants.

Je sais que c'est loin du code que vous avez fourni, mais this.foo = new Foo(a); est proche de l'imaginaire this.foo.SetA(a) que j'ai écrit à titre d'exemple.

Dans votre exemple, il y avait un problème de programmation possible. Le constructeur de Foo et le constructeur StartCommand ont tous les deux la valeur 'a' comme paramètre. Et si vous le rendez public? Et vous êtes très surpris, en réglant le 'a' dans le StartCommand, les changements d'impression, mais Foo se comporte différemment. Le constructeur de Foo a stocké la valeur précédente, et vous pouvez oublier de changer le code de la commande, pour passer la nouvelle valeur à Foo, où vous oubliez de rendre le 'a' public.

Le grattage de l'ensemble de l'exemple peut être évité en supprimant la construction de Foo de Command.

+0

Pour une raison quelconque, je ne peux pas instancier '' Foo'' dans le client, donc je ne peux pas utiliser le modèle de commande _pure_, n'est-ce pas? – user3510462

+0

@ user3510462 J'ai modifié le post. Pourquoi ne pouvez-vous pas instancier 'Foo' dans le client? Pouvez-vous instancier ailleurs, que le 'Command'? – ntohl

+0

'' Foo'' provient d'une bibliothèque tierce et je ne veux aucune dépendance à ce sujet dans mon projet client. – user3510462

0

1) il semble s'agir d'une adaptation au modèle de commande.

2) Foo est récepteur afin qu'il sache comment effectuer une demande. 3) .Ils peuvent être dans la même classe mais ils violent certains principes de conception comme la seule resposabilité. Le but du client dans le modèle de commande est de créer des objets et d'injecter des récepteurs. Le rôle de l'invocateur est de contenir des commandes dans une structure de données. appelant leur méthode d'exécution. Simplement, il planifie les commandes et vous pouvez faire beaucoup de choses comme la journalisation, l'historique des commandes et ainsi de suite. Et mettre ce genre de logique dans le client est trop de fardeau pour le client.