7

I have been brushing up on my design patterns and came across a thought that I could not find a good answer for anywhere. So maybe someone with more experience can help me out.

Is the DAO pattern only meant to be used to access data in a database?

Most the answers I found imply yes; in fact most that talk or write on the DAO pattern tend to automatically assume that you are working with some kind of database.

I disagree though. I could have a DAO like follows:

public interface CountryData {
    public List<Country> getByCriteria(Criteria criteria);
}

public final class SQLCountryData implements CountryData {
    public List<Country> getByCriteria(Criteria criteria) {
        // Get From SQL Database.
    }
}

public final class GraphCountryData implements CountryData {
    public List<Country> getByCriteria(Criteria criteria) {
        // Get From an Injected In-Memory Graph Data Structure.
    }
}

Here I have a DAO interface and 2 implementations, one that works with an SQL database and one that works with say an in-memory graph data structure. Is this correct? Or is the graph implementation meant to be created in some other kind of layer?

And if it is correct, what is the best way to abstract implementation specific details that are required by each DAO implementation?

For example, take the Criteria Class I reference above. Suppose it is like this:

public final class Criteria {
    private String countryName;

    public String getCountryName() {
        return this.countryName;
    }

    public void setCountryName(String countryName) {
        this.countryName = countryName;
    }
}

For the SQLCountryData, it needs to somehow map the countryName property to an SQL identifier so that it can generate the proper SQL. For the GraphCountryData, perhaps some sort of Predicate Object against the countryName property needs to be created to filter out vertices from the graph that fail.

What's the best way to abstract details like this without coupling client code working against the abstract CountryData with implementation specific details like this?

Any thoughts?

EDIT:

The example I included of the Criteria Class is simple enough, but consider if I want to allow the client to construct complex criterias, where they should not only specify the property to filter on, but also the equality operator, logical operators for compound criterias, and the value.

9ee1
  • 1,078
  • 1
  • 10
  • 25
  • 2
    I, for one, do not use DAO just for database access. In my design, I often have a DAO that reads data, just like the name says, from some source. Sometimes, it's a database, other times it might be a file, a particular stream, an encryption device, hardware random number generator, you name it. As long as it supplies me data, and I don't care where the data comes from, I'm comfortable following the DAO pattern. It also makes it easy to refactor code later, what was a SQL database might become some other storage mechanism, with no effect on my application other than on the DAO implementation. – Ewald Nov 09 '11 at 05:33

4 Answers4

5

DAO's are part of the DAL (Data Access Layer) and you can have data backed by any kind of implementation (XML, RDBMS etc.). You just need to ensure that the project instance is injected/used at runtime. DI frameworks like Spring/Guice shine in this case. Also, your Criteria interface/implementation should be generic enough so that only business details are captured (i.e country name criteria) and the actual mapping is again handled by the implementation class.

For SQL, in your case, either you can hand generate SQL, generate it using a helper library like Spring or use a full fledged framework like MyBatis. In our project, Spring XML configuration files were used to decouple the client and the implementation; it might vary in your case.

EDIT: I see that you have raised a similar concern in the previous question. The answer still remains the same. You can add as much flexibility as you want in your interface; you just need to ensure that the implementation is smart enough to make sense of all the arguments it receives and maps them appropriately to the underlying source. In our case, we retrieved the value object from the business layer and converted it to a map in the SQL implementation layer which can be used by MyBatis. Again, this process was pretty much transparent and the only way for the service layer to communicate with DAO was via the interface defined value objects.

Sanjay T. Sharma
  • 22,857
  • 4
  • 59
  • 71
  • Small thought, what if you wanted the client to specfiy a property to order on for example. How would the Criteria object accomdate that so that you can translate it to say a map to pass to MyBatis? Sorry if this seems like a similair question so my last one; I'll admit they are kind of similiar – 9ee1 Nov 09 '11 at 06:00
  • I'd pass along with the criteria (e.g. country name) and a ordering value (object having field name and type of ordering `ASC` or `DESC`). MyBatis is [capable of creating dynamic queries](http://ibatis.apache.org/docs/dotnet/datamapper/ch03s09.html) based on the passed in "value object" or "map" which should take care of the query created. – Sanjay T. Sharma Nov 09 '11 at 06:15
  • I am assuming you mean you would pass along the field name in the database? Or do you mean the "property" name on the value model that you want to order on and in your SQL Map, you would translate it to the appropiate dtabase field name? If the latter, won't there be tons of conditional logic if there as a lot of "properties" in the model? – 9ee1 Nov 09 '11 at 06:32
  • I meant database column name which can be used in dynamic query along with direction (`ASC`, `DESC`). In your SQL DAO implementation, you will read these values and create a map which will be something along the lines; `map.put("sortColumn", ordering.column); map.put("sortOrder", ordering.order); map.put("countryName", myCountryName);`. This map will then be passed to MyBatis and the MyBatis XML will use the map "keys" are propeties when creating queries. – Sanjay T. Sharma Nov 09 '11 at 06:40
  • Right, but that's exactly my point. If the client code is working with an injected instance of your DAO, it is working against the interface not the concrete implementation. So in essense, it has no idea what kind of implementation it is working against. It could be the SQL or Graph as in my examples. So if you force the caller to set an order criteria using the database field name when they are invoking the DAO method, there is an implicit coupling there and the entire idea of the interface is useless. See what I am saying? – 9ee1 Nov 09 '11 at 06:47
  • ... Ran out of characters. Thanks for your detailed answers and for sticking in there with me. I enjoy getting insight from experienced people like yourself. – 9ee1 Nov 09 '11 at 06:48
  • I understand your concern, but it's a non-issue IMO. For the SQL implementation, it is the RDMBS table's column name. For XML based solution, it might be the attribute/element name. After all, when you are "ordering" something, it makes perfect sense to know *what* you are ordering on. It really isn't RMDBS specific but a data store related concept really. – Sanjay T. Sharma Nov 09 '11 at 06:57
  • I agree that it makes sense to know _what_ you are ordering on but I think its a **huge** concern. If one day I decide to change the injected implementation to something else, which is not uncommon, then there would be a ton of refactoring that needs to be done because the new implementation would not necessarily know the it is being passed a database field name. Perhaps some other layer in the middle needs to be introduced? I guess I'll have to think about it some more. Thanks again for your detailed comments, much appreciated. – 9ee1 Nov 09 '11 at 07:04
  • You are of course welcome. BTW, I have been there, done that. It just works. Also, too much thinking is counter productive. If I were you, I would have whipped out a simple working implementation/POC, tried changing underlying datastore and see how it turns out. Unless you "actually" interact with the API you are designing, any more design thought would be nothing more than over engineering. I'm more into a good lightweight initial design and then aggressive refactoring rather than thinking all combinations/design upfront. Of course, YMMV. :) – Sanjay T. Sharma Nov 09 '11 at 07:12
2

No, I don't believe it's tied to only databases. The acronym is for Data Access Object, not "Database Access Object" so it can be usable with any type of data source.

The whole point of it is to separate the application from the backing data store so that the store can be modified at will, provided it still follows the same rules.

That doesn't just mean turfing Oracle and putting in DB2. It could also mean switching to a totally non-DBMS-based solution.

paxdiablo
  • 854,327
  • 234
  • 1,573
  • 1,953
2

ok this is a bit philosophical question, so I'll tell what I'm thinking about it. DAO usually stands for Data Access Object. Here the source of data is not always Data Base, although in real world, implementations are usually come to this. It can be XML, text file, some remote system, or, like you stated in-memory graph of objects.

From what I've seen in real-world project, yes, you right, you should provide different DAO implementations for accessing the data in different ways. In this case one dao goes to DB, and another dao implementation goes to object graph.

The interface of DAO has to be designed very carefully. Your 'Criteria' has to be generic enough to encapsulate the way you're going to get the data from. How to achieve this level of decoupling? The answer can vary depending on your system, by in general, I would say, the answer would be "as usual, by adding an another level of indirection" :)

You can also think about your criteria object as a data object where you supply only the data needed for the query. In this case you won't even need to support different Criteria. Each particular implementation of DAO will take this data and treat it in its own different way: one will construct query for the graph, another will bind this to your SQL.

To minimize hassling with maintenance I would suggest you to use Dependency Management frameworks (like Spring, for example). Usually these frameworks are suited well to instantiate your DAO objects and play good together. Good Luck!

Mark Bramnik
  • 39,963
  • 4
  • 57
  • 97
  • Interesting. Would you mind giving a small explanation what you mean by "another level of indirection"? I am trying to think of a way to design a Criteria object like you said, where client code can specify which a property to filter on, it's operator (=, >, etc.) and value in a generic decoupled manner and have each DAO implemenetation can interpect it however it likes. But I can't seem to figure it out. EDIT: Thanks for the great detailed answer BTW. – 9ee1 Nov 09 '11 at 05:56
1

No, DAO for databases only is a common misconception.

DAO is a "Data Access Object", not a "Database Access Object". Hence anywhere you need to CRUD data to/from ( e.g. file, memory, database, etc.. ), you can use DAO.

In Domain Driven Design there is a Repository pattern. While Repository as a word is far better than three random letters (DAO), the concept is the same.

The purpose of the DAO/Repository pattern is to abstract a backing data store, which can be anything that can hold a state.

tolitius
  • 22,149
  • 6
  • 70
  • 81