DDD: Share entity with multiple aggregate roots - entity

Learning DDD, in our application there are three aggregate roots, different types of forms, all of which needs some PDF to be uploaded. These pdf uploads have some metadata, like who uploaded and when uploaded etc, attached to it so they are stored in their own table.
My question is whether this PDF should be modeled as a value object or an entity or an aggregate root.
For me it looks like an entity named as "Attachment" but then this entity should be shared, only the type not the instances, by all the aggregate root. Is it an allowed practice to use same entity type in multiple roots, if so then which part of the model should take the responsibility for creating this entity.
Update
class Attachment{
Java.io.File pdf;
Date attachedOn;
.....
//no operation for this class
}
#AggregateRoot
class DocumentA {
Set<Attachment> attachments;
Set<DocumentB> supportingDocumentsB;
Set<DocumentA> supportingDocumentsA;
.... //other properties unique to DocumentA
attach(Attachment a);
detach(Attachment a);
addSupportingDocumentA(DocumentA doc);
removeSupportingDocumentA(DocumentA doc);
addSupportingDocumentB(DocumentB doc);
removeSupportingDocumentB(DocumentB doc);
.... //other operations unique to DocumentA
}
#AggregateRoot
class DocumentB {
Set<Attachment> attachments;
Set<DocumentB> supportingDocumentsB;
Set<DocumentA> supportingDocumentsA;
.... //other properties unique to DocumentB
attach(Attachment a);
detach(Attachment a);
addSupportingDocumentA(DocumentA doc);
removeSupportingDocumentA(DocumentA doc);
addSupportingDocumentB(DocumentB doc);
removeSupportingDocumentB(DocumentB doc);
.... //other operations unique to DocumentB
}
#AggregateRoot
class SomeAggregateRoot{
Set<Attachment> attachments;
//some properties
attach(Attachment a);
detach(Attachment a);
//some operations
}
Now the question is how the Attachment class should be modeled, as a value object (or) an entity (or) an aggregate root. Quoting «Domain-Driven Design Distilled», Vaughn Vernon (ISBN-13: 978-0134434421):
Furthermore, a Value Object is not a thing but is often used to describe, quantify, or measure an entity.

I think the Attachment concept fits better in the Value Object concept, since there is no life cycle and the fields are naturally immutable.
The fact that the data base entry has an primary key doesn't imply it has to be an entity in the domain context.

Related

How do I make a well designed validation for a complex collection model?

As input I have a list of Books. As output I expect a SimilarBookCollection.
A SimilarBookCollection has an author, publishYear and list of Books. The SimilarBookCollection can't be created if the author of the books is different or if the publishYear is different.
The solution so far in PHP:
client.php
----
$arrBook = array(...); // array of books
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
$objSimilarBookCollection = new SimilarBookCollection($arrBook);
echo $objSimilarBookCollection->GetAuthor();
}
else {
echo 'Invalid input';
}
SimilarBookCollection.php
---
class SimilarBookCollection() {
public function SimilarBookCollection(array $arrBook) {
$objValidator = new SimilarBookCollectionValidator($arrBook);
if ($objValidator->IsValid()) {
throw new Exception('Invalid books to create collection');
}
$this->author = $arrBook[0]->GetAuthor();
$this->publishYear = $arrBook[0]->GetPublishYear();
$this->books = $arrBook;
}
public function GetAuthor() {
return $this->author;
}
public function GetPublishYear() {
return $this->publishYear;
}
public function GetBooks() {
return $this->books;
}
}
SimilarBookCollectionValidator.php
---
class SimilarBookCollectionValidator() {
public function IsValid() {
$this->ValidateAtLeastOneBook();
$this->ValidateSameAuthor();
$this->ValidateSameYear();
return $this->blnValid;
}
... //actual validation routines
}
The goal is to have a "special" collection with only books that have the same author and publishYear. The idea is to easily access the repeating information like author or year from the object.
How would you name the SimilarBookCollection? The current name is to
generic. Using a name like SameYearAuthorBookCollection looks a bit
long and strange(if more conditions will be added then name will increase)
Would you use a Validator in SimilarBookCollection constructor using a
defensive programming style?
Would you change the design of the code? If yes how?
It all depends ;)
So if I were to aim for a generic adaptable solution I would do the following:
Validator in constructor
On one hand you are validating twice; that is informative in case of a broken precondition/contract (not giving a valid list), but is double the code to run - for what purpose exactly?
If you want to use this in a system depends on its size, how critical it is, product phase, and likely more criterias.
But then it also is controller logic fitted into a model meaning you are spreading your code around.
I would not put it in the constructor.
Name / Design
I would say keep the BookCollection generic as it is, and have any validation strictly in the controller space, instead of bloating the collection which essentially seems to be an array with the extra field of author.
If you want to differentiate between different collection types use either (multiple) inheritance or some sort of additional field "collectionType"; the former if you expect many derivatives or varying functionality to come (also keeps the logic where different nicely separated).
You could also consider your collection as a set on which you perform queries and for convenience's sake you could maintain some sort of meta data like $AuthorCount = N, $publicationDates = array(...) from which you can quickly derive the collection's nature. This approach would also keep your validator-code minimal (or non-existent), as it'd be implicitly in the collection and you could just do the validation in the controller keeping the effective logic behind it clearly visible.
That would also make it more comfortable for you in the future. But the question really is what you want and need it for, and what changes you expect, because you are supposed to fit your design to your requirements and likely changes.
For your very particular problem the constraints as I understand are as follows:
There is only one collection type class in the system at any given
point in time.
The class's items have several attributes, and for a particular, possibly changing subset of these (called identical attributes), the collection only accepts item lists where the chosen attributes of all items are identical.
The class provides getters for all identical attributes
The class must not be usable in any other way than the intended way.
If not for point 1 I would use a generic base class that is either parametrized (ie you tell it upon instantiation which is the set of identical attributes) or uses multiple inheritance (or in php traits) to compose arbitrary combinations with the needed interfaces. Children might rely on the base class but use a predefined subset of the identical attributes.
The parametrized variant might look something as follows:
class BookCollection {
public function __construct($book_list, $identical_fields=array())
{
if (empty($book_list))
{
throw new EmptyCollectionException("Empty book list");
}
$default = $book_list[0];
$this->ia = array();
foreach($identical_fields as $f)
{
$this->ia[$f] = $default->$f;
}
foreach($book_list as $book)
{
foreach($identical_fields as $f)
{
if ($this->ia[$f] !== $book->$f)
{
throw new NotIdenticalFieldException("Field $f is not identical for all");
}
}
}
$this->book_list = $book_list;
}
public function getIdentical($key)
{
$this->ia[$key];
}
}
final class BC_by_Author extends BookCollection{
public function __construct($book_list)
{
parent::__construct($book_list,array('author'));
}
public function getAuthor(){ $this->ia['author']; }
}
or fooling around with abstract and final types (not sure if it's valid like this)
abstract class BookCollection{
public final function __construct($book_list){...}
abstract public function getIdenticalAttributes();
}
final class BC_by_Author {
public function getIdenticalAttributes(){ return array('author'); }
public function getAuthor(){ return $this->ia['author']; }
}
If you rely on getters that do not necessarily match the field names I would go for multiple inheritance/traits.
The naming then would be something like BC_Field1Field2Field3.
Alternatively or additionally, you could also use exactly the same classname but develop your solutions in different namespaces, which would mean you wouldn't have to change your code when you change the namespace, plus you can keep it short in the controllers.
But because there will only ever be one class, I would name it BookCollection and not unnecessarily discuss it any further.
Because of constraint 4, the white box constraint, the given book list must be validated by the class itself, ie in the constructor.

Law of Demeter - Data objects

I'm trying to follow the Law Of Demeter ( see http://en.wikipedia.org/wiki/Law_of_Demeter , http://misko.hevery.com/code-reviewers-guide/flaw-digging-into-collaborators/ ) as I can see the benefits, however I've become a little stuck when it comes to domain objects.
Domain objects do naturally have a chain and sometimes it's necessary to display the information about the entire chain.
For instance, a shopping basket:
Each order contains a user, delivery info and a list of items
Each order item contains a product and quantity
Each product has a name and price.
Each user contains a name and address
The code which displays the order information has to use all the information about the order, users and products.
Surely it's better and more reusable to get this information through the order object e.g. "order.user.address.city" than for some code higher up to do queries for all the objects I listed above then pass them into the code separately?
Any comments/suggestions/tips are welcome!
One problem with using chained references, such as order.user.address.city, is that higher-order dependencies get "baked into" the structure of code outside the class.
Ideally, in cases when you refactor your class, your "forced changes" should be limited to the methods of the class being refactored. When you have multiple chained references in the client code, refactoring drives you to make changes in other places of your code.
Consider an example: suppose that you'd like to replace User with an OrderPlacingParty, an abstraction encapsulating users, companies, and electronic agents that can place an order. This refactoring immediately presents multiple problems:
The User property will be called something else, and it will have a different type
The new property may not have an address that has city in cases when the order is placed by an electronic agent
The human User associated with the order (suppose that your system needs one for legal reasons) may be related to the order indirectly, - for example, by being a designated go-to person in the definition of the OrderPlacingParty.
A solution to these problems would be to pass the order presentation logic everything that it needs directly, rather than having it "understand" the structure of the objects passed in. This way you would be able to localize the changes to the code being refactored, without spreading the changes to other code that is potentially stable.
interface OrderPresenter {
void present(Order order, User user, Address address);
}
interface Address {
...
}
class PhysicalAddress implements Address {
public String getStreetNumber();
public String getCity();
public String getState();
public String getCountry();
}
class ElectronicAddress implements Address {
public URL getUrl();
}
interface OrderPlacingParty {
Address getAddress();
}
interface Order {
OrderPlacingParty getParty();
}
class User implements OrderPlacingParty {
}
class Company implements OrderPlacingParty {
public User getResponsibleUser();
}
class ElectronicAgent implements OrderPlacingParty {
public User getResponsibleUser();
}
I think, when chaining is used to access some property, it is done in two (or at least two) different situation. One is the case that you have mentioned, for example, in your presentation module, you have an Order object and you would like to just display the owner's/user's address, or details like city. In that case, I think it is of not much problem if you do so. Why? Because you are not performing any business logic on the accessed property, which can (potentially) cause tight coupling.
But, things are different if you use such chaining for the purpose of performing some logic on the accessed property. For example, if you have,
String city = order.user.address.city;
...
order.user.address.city = "New York";
This is problematic. Because, this logic is/should more appropriately be performed in a module closer to the target attribute - city. Like, in a place where the Address object is constructed in the first place, or if not that, at least when the User object is constructed (if say User is the entity and address the value type). But, if it goes farther than that, the farther it goes, the more illogical and problematic it becomes. Because there are too many intermediaries are involved between the source and the target.
Thus, according to the the Law of Demeter, if you are performing some logic on the "city" attribute in a class, say OrderAssmebler, which accesses the city attribute in a chain like order.user.address.city, then you should think of moving this logic to a place/module closer to the target.
You're correct and you'll most likely model your value objects something like this
class Order {
User user;
}
class User {
Address shippingAddress;
Address deliveryAddress;
}
class Address {
String city;
...
}
When you start considering how you will persist this data to a database (e.g. ORM) do you start thinking about performance. Think eager vs lazy loading trade offs.
Generally speaking I adhere to the Law of Demeter since it helps to keep changes in a reduced scope, so that a new requirement or a bug fix doesn't spread all over your system. There are other design guidelines that help in this direction, e.g. the ones listed in this article. Having said that, I consider the Law of Demeter (as well as Design Patterns and other similar stuff) as helpful design guidelines that have their trade-offs and that you can break them if you judge it is ok to do so. For example I generally don't test private methods, mainly because it creates fragile tests. However, in some very particular cases I did test an object private method because I considered it to be very important in my app, knowing that that particular test will be subject to changes if the implementation of the object changed. Of course in those cases you have to be extra careful and leave more documentation for other developers explaining why you are doing that. But, in the end, you have to use your good judgement :).
Now, back to the original question. As far as I understand your problem here is writing the (web?) GUI for an object that is the root of a graph of objects that can be accessed through message chains. For that case I would modularize the GUI in a similar way that you created your model, by assigning a view component for each object of your model. As a result you would have classes like OrderView, AddressView, etc that know how to create the HTML for their respective models. You can then compose those views to create your final layout, either by delegating the responsibility to them (e.g. the OrderView creates the AddressView) or by having a Mediator that takes care of composing them and linking them to your model. As an example of the first approach you could have something like this (I'll use PHP for the example, I don't know which language you are using):
class ShoppingBasket
{
protected $orders;
protected $id;
public function getOrders(){...}
public function getId(){...}
}
class Order
{
protected $user;
public function getUser(){...}
}
class User
{
protected $address;
public function getAddress(){...}
}
and then the views:
class ShoppingBasketView
{
protected $basket;
protected $orderViews;
public function __construct($basket)
{
$this->basket = $basket;
$this->orederViews = array();
foreach ($basket->getOrders() as $order)
{
$this->orederViews[] = new OrderView($order);
}
}
public function render()
{
$contents = $this->renderBasketDetails();
$contents .= $this->renderOrders();
return $contents;
}
protected function renderBasketDetails()
{
//Return the HTML representing the basket details
return '<H1>Shopping basket (id=' . $this->basket->getId() .')</H1>';
}
protected function renderOrders()
{
$contents = '<div id="orders">';
foreach ($this->orderViews as $orderView)
{
$contents .= orderViews->render();
}
$contents .= '</div>';
return $contents;
}
}
class OrderView
{
//The same basic pattern; store your domain model object
//and create the related sub-views
public function render()
{
$contents = $this->renderOrderDetails();
$contents .= $this->renderSubViews();
return $contents;
}
protected function renderOrderDetails()
{
//Return the HTML representing the order details
}
protected function renderOrders()
{
//Return the HTML representing the subviews by
//forwarding the render() message
}
}
and in your view.php you would do something like:
$basket = //Get the basket based on the session credentials
$view = new ShoppingBasketView($basket);
echo $view->render();
This approach is based on a component model, where the views are treated as composable components. In this schema you respect the object's boundaries and each view has a single responsibility.
Edit (Added based on the OP comment)
I'll assume that there is no way of organizing the views in subviews and that you need to render the basket id, order date and user name in a single line. As I said in the comment, for that case I would make sure that the "bad" access is performed in a single, well documented place, leaving the view unaware of this.
class MixedView
{
protected $basketId;
protected $orderDate;
protected $userName;
public function __construct($basketId, $orderDate, $userName)
{
//Set internal state
}
public function render()
{
return '<H2>' . $this->userName . "'s basket (" . $this->basketId . ")<H2> " .
'<p>Last order placed on: ' . $this->orderDate. '</p>';
}
}
class ViewBuilder
{
protected $basket;
public function __construct($basket)
{
$this->basket = $basket;
}
public function getView()
{
$basketId = $this->basket->getID();
$orderDate = $this->basket->getLastOrder()->getDate();
$userName = $this->basket->getUser()->getName();
return new MixedView($basketId, $orderDate, $userName);
}
}
If later on you rearrange your domain model and your ShoppingBasket class can't implement the getUser() message anymore then you will have to change a single point in your application, avoid having that change spread all over your system.
HTH
The Law Of Demeter is about calling methods, not accessing properties/fields. I know technically properties are methods, but logically they're meant to be data. So, your example of order.user.address.city seems fine to me.
This article is interesting further reading: http://haacked.com/archive/2009/07/13/law-of-demeter-dot-counting.aspx

OO design of Books and Tags

I'm doing a basic exercise of object-oriented design for a simple use case: A Book can be tagged with many Tags.
I have many solutions, and I would like your input on which is better in term of OOD principles and maintanability.
Option 1
public class Book {
private String title;
//... other attributes
private List<Tag> tags;
}
The thing that bothers me is that we mixed core attributes of a Book with additional categorization or search data. I may have in the future a requirement where certain Books can't be tagged. In the future, the Book class can become bloated when I add more responsabilities: category, list of users that read it, ratings...
Option 2
public class TaggedBook extends Book {
private Book book;
private List<Tag> tags;
}
I think this is similar to the Decorator pattern, but I don't see it fit here because I'm not extending behavior.
Option 3
Decouple Books and Tags comnpletely, and use a service to retrieve Tags from a book (given each Book has a unique identifier)
List<Tag> TagService.getTags(Book book)
However, I don't find this solution very elegant (is it?), and I may have to send two queries: one to retrieve the book, the other for the tags.
I am planning on applying the best options to other requirements: A Book has a rating, a Book can be categorized...
I'm also planning on using a DMS to store Books and Tags objects. Since it's not a relations database, its schema will likely correspond to the class design.
Thank you
All three options can be valid and good choices for your class design. It all depends on the complete context/requirements. The requirement you listed are very likely not enough to make the "right" decision. For example, if your application is rather book centric and tags do not need to evolve or be authored independently from books, option 3 would probably introduce unnecessary complexity. If you design a public API that acts as a facade around your actual logic you still might go for option 1 or 2 even though internally both Book and Tag are totally decoupled aggregate roots. Scalability, performance, extensibilty ... those are all possible requirements that you need to balance and that will influence your design.
If you are looking for a good formalized methodology and guidance for class design for enterprise applications, I'd suggest you look into Domain Driven Design.
Also, do not design you classes for unknown future requirements. This will also again add useless complexity (think: cost). Just make sure you have enough unit test that cover your back when you need to refactor for new requirements.
The concept of decorator pattern fits well in your case.But I think strategy pattern
is more useful and effective in you case.If you don't know about strategy pattern then Take a look on This.It will give you a good idea on strategy pattern.If you need more suggestion or have any query then ask in comment.
Thank you
All the best..
If Books are not the only Entity in your Model that can be tagged. I'll go with this interface:
public interface Taggeable {
public List<Tag> getTags();
public void setTags (List<Tag> tags)
}
And
public class Book implements Taggeable {
//Book attributes and methods
The kinds of Books/Entities that can be Tagged only need to implement this interface. That way, you can have Book objects that allow tagging and others that doesn't. Also, the tagging mechanism can be used with other Objects of your model.
I think it would be better to mix pattern for a better solution. Remember a particular pattern only solves one particular problem.
My suggestion is to isolate different interfaces and join them accordingly. The base class should have the ability to query for supported interfaces, so that it can call the appropriate interface functions.
First interface is the query supported interface:
public interface QueryInterface {
public boolean isTaggable();
public boolean isRatable();
}
...next comes particular interfaces.
Suppose the first particular interface is taggable:
public interface Taggable {
public Vector<Tag> getTags();
public boolean addTag(Tag newTag);
}
...and the second one is rateable...
public interface Rateable {
public Rating getRating();
public void setRating(Rating newRating);
}
The plain old base class itself: :)
public class Book implements QueryInterface {
private String title;
public boolean isTaggable() {
return false;
}
public boolean isRateable() {
return false;
}
}
Now the special derived class which complies to the taggable interface:
public class TaggedBook extends Book implements Taggable {
private Vector<Tag> tags;
public Vector<Tag> getTags() {
return tags;
}
#override
public boolean isTaggable() {
return true;
}
public boolean addTag(Tag newTag) {
return tags.insert(newTag);
}
}
...and the different book which is rateable only:
public class RatedBook extends Book implements Rateable {
private Rating rating;
public Rating getRating() {
return rating;
}
public void setRating(Rating newRating) {
this.rating = newRating;
}
#override
public boolean isRateable() {
return true;
}
}
Hope this helps. :)
Option 1
The first solution supports the concept of a has-a relationship. I don't see that there is any drawback to this design. You say there is a possibility of code bloat when you add responsibilities to the class, however this is a completely separate issue (breaking the S in SOLID). A class with many members is not inherently a bad thing (It can sometimes be an indication that something has gone wrong, but not always).
The other problem you give is that in the future you might have a Book without Tags. Since I do not know the whole picture I am only guessing, but I would argue strongly that this Book would/could simply be a Book with 0 Tags.
Option 3
I think that this is the non OO way of doing things. Implementing a has-a relationship by association of some ID. I don't like it at all.
For each additional property you wanted to add to a Book you would need to also create an appropriate Service type object and make lots of additional and unnecessary calls with no benefit for doing so over Option 1 that i can see.
Another reason that i don't like this is that this implies that a Tag has a has-a relationship with books. I don't think that they do.
Option 2
This is not good in my opinion, but that is mostly because i think the decorator pattern was not designed for use in this sort of situation, and because you would likely need to make use of rtti to be able to use your resulting objects, or implement a lot of empty methods in your base class.
I think that your first solution is overwhelmingly the best. If you are worried about code bloat you may consider having a Tags object as a member of Book, which is responsible for searching itself (This also helps with the S in SOLID) and the same for any additional properties of Book. If a Book has no tags then Tags would simply return false when queried, and Book would echo that.
Summary
For such a simple problem, don't over think it. The basic principles of OO design (has-a, is-a) are the most important.
I would suggest to think about it as a design problem first, and then try to express the design in code.
So, we have to decide what classes (entities) we have. The Book is a class because is central to the problem, has distinct instances and, probably, several attributes and operations. The Tag may be both a value-object and a class.
Let us consider the first option. It can be a value object because it does not have internal structure, any operations, and its instances may not be distinct. Thus a Tag can be thought of as a String marker. This way, Book has an attribute, say, tags that contains a collection of tag values. Values can be added and removed without any restrictions. Books can be searched by tags where tags are supplied by value. It is difficult t get a complete list of tags or get all books for a specific tag.
Now, the second option. The Tag can also be a class because it is related to another class (Book) and its instances may be distinct. Then we have two classes: Book and Tag, and a 'many-to-many' association between them - TaggedWith. As you may know, association is a sort of a class itself besides being a relation. Instances of TaggedWith association (links) connect instances of Book and Tag. Next we have to decide which class will be responsible for managing correspondence (create, read, lookup, destroy, update...) between Book and Tag. Most natural choice here is to assign this responsibility to the association TaggedWith.
Lets write some code.
Option 1
public class Book {
private Collection<String> tags;
/* methods to work with tags, e.g. */
public void addTag(String tag) {...}
public String[] getAllTags() {...}
...
}
It may look complex, but actually similar code can just be generated from the design description in a couple of mouse clicks. On the other hand, if you use DB a lot of code here becomes SQL queries.
Option 2
public class Tag {
/* we may wish to define a readable unique id for Tag instances */
#Id
private String name;
/* if you need navigation from tags to books */
private Collection<Book> taggedBooks;
public Collection<Book> getTaggedBooks() {...}
public void addBook(Book book) {...} // calls TaggedWith.create(this, book)
public void _addBook(Book book) {...} // adds book to taggedBooks
....
/* I think you get the idea */
/* methods to work with tags */
public String getName() {...}
...
/* Tags cannot be created without id (i.e. primary key...) */
public Tag(String name) {...}
/* if you'd like to know all tags in the system,
you have to implement 'lookup' methods.
For this simple case, they may be put here.
We implement Factory Method and Singleton patterns here.
Also, change constructor visibility to private / protected.
*/
protected static HashMap<String, Tag> tags = ...; // you may wish to use a DB table instead
public static Tag getInstance(String name) {...} // this would transform to DAO for DB
}
public class Book {
/* if we need an id */
#Id // made up
private String bookId;
/* constructors and lookup the same as for Tag
If you wish to use a database, consider introducing data access layer or use ORM
*/
/* if you need navigation from Book to Tag */
private Collection<Tag> tags;
public Collection<Tag> getTags() {...}
...
}
public TaggedWith {
/* constructor and lookup the same as for Tag and Book (!) */
/* manage ends of the association */
private Book book;
private Tag tag;
public Book getBook() {...}
public Tag getTag() {...}
protected TaggedWith(Book book, Tag tag) {
this.book = book;
this.tag = tag;
book._addTag(tag); // if you need navigation from books to tags
tag._addBook(book); // if you need navigation from tags to books
}
/* if you need to search tags by books and books by tags */
private static Collection<TaggedWith> tagsBooks = ...;
public static TaggedWith create(Tag tag, Book book) {
// create new TaggedWith and add it to tagsBooks
}
}
I prefer the 3rd option, to separate them completely.
Books and tags have a mang-to-many relationship, by separating them, you can make it easier to make queries like "which books got tagged by 'Computer Science'".
Unless either the order of the tags on a book matters or a book can have the same tag twice, you should store your tags in a set rather than a list.
Once you've done that, I'd go with something like the third option. It seems to me that the books don't own the tags and the tags don't own the books (indeed, you'd want to look this up either way, probably). Later, when you want to associate other things with your books (e.g. reviews, ratings, libraries) you can create another association without modifying the book class.
I would do it totally different. Thinking a bit like labels in Gmail, I would make it so it would be easier to actually look for books with certain tags rather than find what tags are on the book. Namely, tags work as a filter to find books, not the other way around.
public interface ITaggable
{
string Name { get; }
}
public class Book : ITaggable
{
}
public class Tag
{
private List<ITaggable> objects;
private String name;
public void AddObject() {}
public void RemoveObject() {}
public void HasObject() {}
}
public class TagManager
{
private List<Tag> tags;
private void InitFromDatabase() {}
public void GetTagsForObject(o: ITaggable) {}
public void GetObjectsForTag(objectName: String) {} //
public void GetObjectsForTag(t: Tag) {} //
public void GetObjectsForTag(tagName: String) {} //
public void GetAllTags();
}
... somewhere else ...
public void SearchForTag(tag: Tag)
{
TagManager tagManager = new TagManager();
// Give me all tags with
List<ITaggable> books = tagManager.GetObjectsForTag("History");
}

"Tell, Don't Ask" over multiple domain objects

Question
How do I adhere to the "Tell, Don't Ask" principle when performing a function involving multiple objects.
Example - Generating a Report
I have the following objects (illustrative purposes only):
Car, Horse, Rabbit
There is no relationship between these objects, but I do want to generate a Report based on these objects:
createHtmlReport(Car car, Horse horse, Rabbit rabbit){
Report report = new Report()
report.setSomeField(car.getSerialNumber())
report.setAnotherField(horse.getNumberOfLegs())
// ...etc
}
The problem with this method is that it has to "Pull" data from each object, which violates the "Tell, Don't Ask" rule. I would rather keep the insides of each object hidden, and have them generate a report for me:
car.createHtmlReport()
horse.createHtmlReport()
rabbit.createHtmlReport()
... but then I get 3 partial reports. Furthermore, I don't think a Rabbit should have to know how to generate every single report I need (HTML, JMS, XML, JSON ....).
Finally, whilst generating the report I may want to switch on multiple items:
if (car.getWheels() == 4 || horse.getLegs() == 4)
// do something
The report should maintain the ability to create its self.
In this case, each IReportable object should Implement void UpdateReport(Report aReport).
When Report.CreateReport(List<Reportable> aList) is invoked, it iterates through the List and each object in its own implementation of UpdateReport invokes:
aReport.AddCar(serialNumber)
aReport.AddHorse(horseName)
At the end of CreateReport, the report object should produce its own result.
The goal of "Tell don't ask" rule is to help you identify situations where the responsibility that should lie with the given object ends up being implemented outside of it (bad thing).
What responsibilities can we see in your case? What I see is:
1) knowing how to format the report (in xml, ascii, html, etc)
2) knowing what goes on which report
First one obviously does not belong with the domain object (Car, Horse etc.). Where should the 2) go? One could suggest the domain object but if there are multiple different reports in your system you end up burdening your objects with knowledge about differnt report details which would look and smell bad. Not to mention that it would violate the Single Responsibility Principle: being a Rabbit is one thing but knowing which parts of Rabbit information should go on report X vs. report Y is quite another.
Thus I would design classes which encapsulate data contents that go on a specific type of report (and possibly perform necessary calculations). I would not worry about them reading the data members of Rabbit, Horse or Car. The responsibility this class implements is 'gathering the data for a specific type of a report' which you've consciously decided should lie outside of the domain object.
That's exactly what the Visitor Pattern is for.
I don't know exactly this pattern's name (Visitor, Builder, ...):
public interface HorseView {
void showNumberOfLegs(int number);
}
public interface CarView {
void showNumberOfWheels(int number);
void showSerialNumber(String serialNumber);
}
public class Horse {
void show(HorseView view) {
view.showNumberOfLegs(this.numberOfLegs);
}
}
public class Car {
void show(CarView view) {
view.showNumberOfWheels(this.numberOfWheels);
view.showSerialNumber(this.serialNumber);
}
}
public class HtmlReport implements HorseView, CarView {
public void showNumberOfLegs(int number) {
...
}
public void showNumberOfWheels(int number) {
...
}
public void showSerialNumber(String serialNumber) {
...
}
}
public XmlModel implements HorseView, CarView {
...
}
public JsonModel implements HorseView, CarView {
...
}
This way you can have multiple representations of the same domain object, not violating "Tell don't ask" principle.

The Object-Oriented way to separate the model from its representation

Suppose we have an object that represents the configuration of a piece of hardware. For the sake of argument, a temperature controller (TempController). It contains one property, the setpoint temperature.
I need to save this configuration to a file for use in some other device. The file format (FormatA) is set in stone. I don't want the TempController object to know about the file format... it's just not relevant to that object. So I make another object, "FormatAExporter", that transforms the TempController into the desired output.
A year later we make a new temperature controller, let's call it "AdvancedTempController", that not only has a setpoint but also has rate control, meaning one or two more properties. A new file format is also invented to store those properties... let's call it FormatB.
Both file formats are capable of representing both devices ( assume AdvancedTempController has reasonable defaults if it lacks settings ).
So here is the problem: Without using 'isa' or some other "cheating" way to figure out what type of object I have, how can FormatBExporter handle both cases?
My first instinct is to have a method in each temperature controller that can provide a customer exporter for that class, e.g., TempController.getExporter() and AdvancedTempController.getExporter(). This doesn't support multiple file formats well.
The only other approach that springs to mind is to have a method in each temperature controller that returns a list of properties and their values, and then the formatter can decide how to output those. It'd work, but that seems convoluted.
UPDATE: Upon further work, that latter approach doesn't really work well. If all your types are simple it might, but if your properties are Objects then you end up just pushing the problem down a level... you are forced to return a pair of String,Object values, and the exporter will have to know what the Objects actually are to make use of them. So it just pushes the problem to another level.
Are there any suggestions for how I might keep this flexible?
What you can do is let the TempControllers be responsible for persisting itself using a generic archiver.
class TempController
{
private Temperature _setPoint;
public Temperature SetPoint { get; set;}
public ImportFrom(Archive archive)
{
SetPoint = archive.Read("SetPoint");
}
public ExportTo(Archive archive)
{
archive.Write("SetPoint", SetPoint);
}
}
class AdvancedTempController
{
private Temperature _setPoint;
private Rate _rateControl;
public Temperature SetPoint { get; set;}
public Rate RateControl { get; set;}
public ImportFrom(Archive archive)
{
SetPoint = archive.Read("SetPoint");
RateControl = archive.ReadWithDefault("RateControl", Rate.Zero);
}
public ExportTo(Archive archive)
{
archive.Write("SetPoint", SetPoint);
archive.Write("RateControl", RateControl);
}
}
By keeping it this way, the controllers do not care how the actual values are stored but you are still keeping the internals of the object well encapsulated.
Now you can define an abstract Archive class that all archive classes can implement.
abstract class Archive
{
public abstract object Read(string key);
public abstract object ReadWithDefault(string key, object defaultValue);
public abstract void Write(string key);
}
FormatA archiver can do it one way, and FormatB archive can do it another.
class FormatAArchive : Archive
{
public object Read(string key)
{
// read stuff
}
public object ReadWithDefault(string key, object defaultValue)
{
// if store contains key, read stuff
// else return default value
}
public void Write(string key)
{
// write stuff
}
}
class FormatBArchive : Archive
{
public object Read(string key)
{
// read stuff
}
public object ReadWithDefault(string key, object defaultValue)
{
// if store contains key, read stuff
// else return default value
}
public void Write(string key)
{
// write stuff
}
}
You can add in another Controller type and pass it whatever formatter. You can also create another formatter and pass it to whichever controller.
In C# or other languages that support this you can do this:
class TempController {
int SetPoint;
}
class AdvancedTempController : TempController {
int Rate;
}
class FormatAExporter {
void Export(TempController tc) {
Write(tc.SetPoint);
}
}
class FormatBExporter {
void Export(TempController tc) {
if (tc is AdvancedTempController) {
Write((tc as AdvancedTempController).Rate);
}
Write(tc.SetPoint);
}
}
I'd have the "temp controller", through a getState method, return a map (e.g. in Python a dict, in Javascript an object, in C++ a std::map or std::hashmap, etc, etc) of its properties and current values -- what's convoluted about it?! Could hardly be simpler, it's totally extensible, and totally decoupled from the use it's put to (displaying, serializing, &c).
Well, a lot of that depends on the file formats you're talking about.
If they're based on key/value combinations (including nested ones, like xml), then having some kind of intermediate memory object that's loosely typed that can be thrown at the appropriate file format writer is a good way to do it.
If not, then you've got a scenario where you've got four combinations of objects and file formats, with custom logic for each scenario. In that case, it may not be possible to have a single representation for each file format that can deal with either controller. In other words, if you can't generalize the file format writer, you can't generalize it.
I don't really like the idea of the controllers having exporters - I'm just not a fan of objects knowing about storage mechanisms and whatnot (they may know about the concept of storage, and have a specific instance given to them via some DI mechanism). But I think you're in agreement with that, and for pretty much the same reasons.
If FormatBExporter takes an AdvancedTempController, then you can make a bridge class that makes TempController conform to AdvancedTempController. You may need to add some sort of getFormat() function to AdvancedTempController though.
For example:
FormatBExporter exporterB;
TempController tempController;
AdvancedTempController bridged = TempToAdvancedTempBridge(tempController);
exporterB.export(bridged);
There is also the option of using a key-to-value mapping scheme. FormatAExporter exports/imports a value for key "setpoint". FormatBExporter exports/imports a values for keys "setpoint" and "ratecontrol". This way, old FormatAExporter can still read the new file format (it just ignores "ratecontrol") and FormatBExporter can read the old file format (if "ratecontrol" is missing, it uses a default).
In the OO model, the object methods as a collective is the controller. It's more useful to separate your program in to the M and V and not so much the C if you're programming using OO.
I guess this is the where the Factory method pattern would apply