Path: csiph.com!x330-a1.tempe.blueboxinc.net!newsfeed.hal-mli.net!feeder1.hal-mli.net!news.glorb.com!npeer01.iad.highwinds-media.com!news.highwinds-media.com!feed-me.highwinds-media.com!post01.iad.highwinds-media.com!newsfe01.iad.POSTED!8ad76e89!not-for-mail From: Arved Sandstrom User-Agent: Mozilla/5.0 (X11; U; Linux i686; en-US; rv:1.9.2.17) Gecko/20110424 Lightning/1.0b2 Thunderbird/3.1.10 MIME-Version: 1.0 Newsgroups: comp.lang.java.programmer Subject: Re: "Program to an interface" - When to break a design pattern References: <9dt5s6dalhetgfe99qs92c02hf0dbas44e@4ax.com> In-Reply-To: <9dt5s6dalhetgfe99qs92c02hf0dbas44e@4ax.com> Content-Type: text/plain; charset=ISO-8859-1 Content-Transfer-Encoding: 7bit Lines: 82 Message-ID: X-Complaints-To: abuse@newsgroups-download.com NNTP-Posting-Date: Thu, 05 May 2011 21:26:36 UTC Organization: Public Usenet Newsgroup Access Date: Thu, 05 May 2011 18:26:35 -0300 Xref: x330-a1.tempe.blueboxinc.net comp.lang.java.programmer:3601 On 11-05-05 04:21 PM, Zapanaz wrote: > > I've seen this design pattern before > > http://witte-consulting.com/documents/design-principles/ > > and, in general, I see the point of it. > > But say we've got something like this > > LinkedHashMap sortedMap = this.getSortedMap(); Except it's not sorted. It has "predictable iteration order", but it's not sorted. > > So you have the method > > public LinkedHashMap getSortedMap() { > //do stuff > } > > (not necessarily public) > > Now the design principle says, the method signature should instead be > > public Map getSortedMap() { > //do stuff > } That design principle is "program to an interface" (i.e. to behaviour rather than implementation), and it's a good _general_ idea. Specifically, the design principle means that you return something of the most general type *that satisfies client requirements*. An applicable rule of thumb is that you return what all (or nearly all) of the calling code can use without downcasting, which is generally an ungood thing to do. A related rule is that client requirements include contracts, which in this case has to do with the predictable iteration ordering of LinkedHashMap - Map does not have that. > The problem is, where I'm creating sortedMap above, I need the map to > retain the insertion order. If what's returned actually is a Map, > rather than a LinkedHashMap, then the results the user actually sees > are going to be in the wrong order. Making things worse, in this case, > nothing would actually break, only the end user would notice anything > was actually wrong. No, this is _not_ one of the problems at hand. If you constructed a LinkedHashMap then that instance will remain a LinkedHashMap regardless of whether you return it as a Map or a HashMap or an AbstractMap. Or even a Cloneable. > So in this case, it seems to me, that using LinkedHashMap in the > method signature makes sense. The fact that the return retains the > insertion order is an integral part of what the method does. In this particular case I'd return LinkedHashMap also. That's what you need. The danger of returning a Map is that client code will be written against Map, and in theory any implementation of that very high-level interface can be substituted. > If nothing else, it's going to save Fred Developer down the line from > looking at the code around this > > Map sortedMap = this.getSortedMap(); > > and thinking "wait, how do I know getSortedMap() is going to return a > result with the right ordering?", and having to waste time digging > into that method. As I alluded to above, I'd make Fred's life easier by not referring to it as a sorted map. The method signature public LinkedHashMap getMap() adequately documents things for Fred, and doesn't make the mistake of implying sorting. As Jim Janney mentioned, don't program to an interface if it's that specific implementation that you must have. AHS