2017-10-18 12 views
3

Disons que j'ai une classe Order. Un Order peut être terminé en appelant la méthode Order.finish(). En interne, lorsqu'une Order est terminée, une date d'arrivée est fixée:Comment respecter l'encapsulation lors du stockage de données dans des applications centrées sur un domaine?

Order.java

public void finish() { 
    finishingDate = new Date(); 
} 

Dans la logique métier de l'application, il n'y a pas besoin d'exposer une Order « s finishingDate, il est un domaine privé sans getter. Imaginez qu'après avoir terminé un Order, je veux le mettre à jour dans une base de données. Par exemple, je pourrais avoir un OTI avec une méthode update:

OrderDao.java

public void update(Order order) { 
    //UPDATE FROM ORDERS SET ... 
} 

Dans cette méthode, je dois l'état interne du Order, afin de mettre à jour la table des champs. Mais je l'ai déjà dit, il n'y a aucun besoin dans ma logique métier d'exposer le champ finishingDate de Order.

Si j'ajoute une méthode Order.getFinishingDate():

  1. Je change le contrat de Order classe sans ajouter de la valeur commerciale, UBT pour des raisons « techniques » (une UPDATE dans une base de données)
  2. Je suis violer le principe de l'encapsulation de la programmation orientée objet, puisque j'expose l'état interne.

Comment avez-vous résolu ceci? Pensez-vous que l'ajout de getters (comme les classes "entity" dans ORM) est acceptable?

J'ai vu une approche différente où la classe elle-même (implémentation) sait même comment persister elle-même. Quelque chose comme ceci (exemple très naïve, il est juste pour la question):

public interface Order { 
    void finish(); 
    boolean isFinished(); 
} 

public class DbOrder implements Order { 

    private final int id; 
    private final Database db; 

    //ctor. An implementation of Database is injected 

    @Override 
    public void finish() { 
     db.update("ORDERS", "FINISHING_DATE", new Date(), "ID=" + id); 
    } 

    @Override 
    public boolean isFinished() { 
     Date finishingDate = db.select("ORDERS", "FINISHING_DATE", "ID=" + id); 
     return finishingDate != null; 
    } 

} 

public interface Database { 
    void update(String table, String columnName, Object newValue, String whereClause); 
    void select(String table, String columnName, String whereClause); 
} 

Outre les problèmes de performance (en fait, il peut être mis en mémoire cache ou quelque chose), j'aime cette approche, mais il nous oblige à se moquer de beaucoup de choses lors du test, puisque toute la logique n'est pas "en mémoire". Je veux dire, les données requises pour "exécuter" la logique sous test n'est pas seulement un champ en mémoire, mais il est fourni par un composant externe: dans ce cas, le Database.

Répondre

2

Ceci est une excellente observation à mon avis. Non, je ne considère pas d'ajouter des méthodes uniquement pour des raisons techniques acceptables, en particulier les getters. Je dois admettre cependant que la majorité des gens avec qui j'ai travaillé ajouteraient simplement les getters et n'y penseraient pas en détail comme vous. Ok, alors comment pouvons-nous résoudre le problème de la persistance de quelque chose à laquelle nous n'avons pas accès? Eh bien, juste demander à l'objet de persister lui-même.

Vous pouvez utiliser une méthode persist() (ou autre) sur l'objet lui-même. C'est ok, car cela fait partie du business. Si ce n'est pas le cas, pensez à ce que est. Est-ce sendToBackend() peut-être?Cela ne signifie pas que vous devez mettre les détails de la persistance dans l'objet!

La méthode elle-même peut être aussi supprimée de la persistance réelle que vous le souhaitez. Vous pouvez lui donner des interfaces en tant que paramètres, ou il peut retourner un autre objet qui peut être utilisé plus loin dans la ligne.

Voir ces réponses sur les mêmes problèmes pour la présentation:

Returning a Data Structure to Display information

Encapsulation and Getters

+0

Merci d'avoir répondu à Robert. Il m'est difficile de voir la méthode 'persist()' faire partie de l'entreprise, en fait. Que pensez-vous de l'approche que je viens de poster? Vérifiez la question modifiée. Encore merci –

+1

J'aime bien cette idée, bien qu'elle ne puisse être utilisée que si toute la logique est déléguée à la BD, ce qui n'est pas toujours le cas. Mais bien sûr, vous n'avez pas besoin d'avoir une méthode 'persist()' si l'objet sait quand le faire quand même. Par exemple, la logique 'finish()' pourrait inclure la persistance de l'état actuel dans la base de données automatiquement. Tout dépend des exigences et de la sémantique exactes. –