• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other Pie Elite all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Tim Cooke
  • Liutauras Vilda
  • Jeanne Boyarsky
  • paul wheaton
Sheriffs:
  • Ron McLeod
  • Devaka Cooray
  • Henry Wong
Saloon Keepers:
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Tim Moores
  • Mikalai Zaikin
Bartenders:
  • Frits Walraven

[ Design question ] Avoiding inheritance

 
Ranch Hand
Posts: 782
Python Chrome Ubuntu
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Greetings,

Consider this environment: The core abstraction is an "Address". Some list of responsibilities:
  • knows about its status
  • knows its unique URI, i.e. the unique thing that identifies it
  • can disable itself

  • Now I have another type of Address which I'll call "SpecialAddress". "SpecialAddress" is in essence an Address except that it will have additional properties. One of them is that SpecialAddress has a "cost" attached to it.

    In traditional OO, you would certainly use "extends". But I want to avoid using inheritance. My initial design is to create two interfaces like this:

    Any comments? Any suggestions ?
     
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Why are you trying to avoid inheritance?
     
    Pho Tek
    Ranch Hand
    Posts: 782
    Python Chrome Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    To be specific, I'm trying to avoid "implementation inheritance". I can live with "interface inheritance". As for why; I'd say because most of the experts in the field, opine that inheritance is evil. For example, Allen Holub talked about the fragile base class issue in his book http://www.holub.com/goodies/patterns/index.html and even the GoF's Design patterns book says "Favor composition over inheritance". Ditto Joshua Bloch.
     
    Ranch Hand
    Posts: 580
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    The Decorator (aka Wrapper) pattern is a good way to extend the behaviour of a class without using inheritance.
    D.
     
    Don Kiddick
    Ranch Hand
    Posts: 580
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    You could use the interfaces you describe with the decorator pattern thusly.



    Actually, I'm not quite sure if this is exactly the Decorator pattern. It certainly is the delegation pattern.

    D.
     
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Don Kiddick:

    Actually, I'm not quite sure if this is exactly the Decorator pattern.



    In my understanding, the Decorator polymorphically adds functionality to an existing method and doesn't change (extend) the interface.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Pho Tek:
    In traditional OO, you would certainly use "extends".



    Not sure wether there is something like "traditional" OO.

    It's true that many people think (and even teach ) inheritance should be used whenever there is an imagined "is-a relationship" between two entities. I think that is mainly because of a misinterpretation of a *heuristic* for OO beginners, probably fuelled by the marketing hype that OO somehow would be good at "modelling the real world". :sigh:

    But I want to avoid using inheritance.



    Avoiding inheritance might be an interesting experiment, but it is by no means the path to good OO design.

    The myriads of "inheritance considered harmful" articles is just a reaction to inheritance being almost invariably *overused* and *misused* by beginners.

    Experienced OO developers use inheritance all the time - the Template Method is a very powerfull pattern, for example.

    Inheritance has it's costs, as has composition/delegation (mostly the latter is more flexible, with the cost of a more complex structure). A good developer doesn't avoid one or the other, but has the experience to evaluate the pros and cons for a specific situation, and the skill to refactor from one solution to the other when necessary.

    In your example, I'd probably start with inheritance. Only if the classes become more complex, or the opportunity for reuse shows up, I'd refactor to composition. But I needed to be there to be sure.
    [ December 20, 2004: Message edited by: Ilja Preuss ]
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Pho Tek:

    To be specific, I'm trying to avoid "implementation inheritance". I can live with "interface inheritance". As for why; I'd say because most of the experts in the field, opine that inheritance is evil.

    Actually, there are many experts, perhaps a majority, who think inheritance is what it's about. This is especially true in academia and certain specialized fields like robotics.

    It's just that experts who feel that way tend to avoid languages that are limited to single inheritance, so we don't hear from them much in the Java world.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Warren Dew:
    Actually, there are many experts, perhaps a majority, who think inheritance is what it's about. This is especially true in academia and certain specialized fields like robotics.



    Well, I don't know about robotics, but I often wonder how relevant the "expert opinion" of an academic person really is to someone "in the trenches"...


    It's just that experts who feel that way tend to avoid languages that are limited to single inheritance, so we don't hear from them much in the Java world.



    To me, multiple inheritance hardly is the main issue. Implementation inheritance simply is a technique that results in stronger coupling and less opportunity for reuse. Sometimes it's worth it, often not. A "nice" example for the latter is having java.util.Stack inherit from java.util.Vector. (In fact this can't even be justified by an "is-a relationship"...)
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ilja Preuss:

    To me, multiple inheritance hardly is the main issue. Implementation inheritance simply is a technique that results in stronger coupling and less opportunity for reuse.

    Relative to interface inheritance or relative to delegation?

    Implementation inheritance certainly provides better code reuse than interface inheritance: when inheriting only the interface, one must provide one's own implementation, rather than reusing the implementation of the parent.

    Using delegation rather than inheritance provides nearly as good code reuse, but doesn't expose any inherited interface.

    It's when one wants to inherit an interface and also delegate implementation of its methods that implementation inheritance is useful. In most applications, one doesn't want to do both with more than one parent, which is why Java gets away with only single inheritance. Apparently robotics and certain computer science research areas just happen to be areas where one actually does frequently want to do both with more than one parent, thus the desire for multiple inheritance.
    [ December 21, 2004: Message edited by: Warren Dew ]
     
    Pho Tek
    Ranch Hand
    Posts: 782
    Python Chrome Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ilja,

    I took a look at the Template pattern and agree that it's a good use of inheritance. Reading the discussions lead me to think that "implementation inheritance" has its utility. e.g. Adapter pattern and Abstract classes. But then again, the question should be ask how many pattern in GoF actually use inheritance e.g. Template ? If I have time, I might just do a quick rundown to tally it.
     
    Ranch Hand
    Posts: 872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Inheritance implemented wrongly can lead to ugly dependences and fragile trees. Keeping methods small and making them static is the best way of reuse.

    Keap it simple.
     
    Gerald Davis
    Ranch Hand
    Posts: 872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Ilja Preuss:


    To me, multiple inheritance hardly is the main issue. Implementation inheritance simply is a technique that results in stronger coupling and less opportunity for reuse. Sometimes it's worth it, often not. A "nice" example for the latter is having java.util.Stack inherit from java.util.Vector. (In fact this can't even be justified by an "is-a relationship"...)



    Wise word. I encourage the use Interfaces instead Abstract classes.
     
    High Plains Drifter
    Posts: 7289
    Netbeans IDE VI Editor
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Joshua Bloch, on this point, says "Favor composition over inheritance." (italics are mine)

    I agree with Ilja. Eschewing inheritance in OO programming is rather like while writing a novel without using the letter 'e'. What's the point, other than demonstrating that it can be done?
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Gerald Davis:
    Inheritance implemented wrongly can lead to ugly dependences and fragile trees.



    Certainly. And used wisely, it can lead to well managed dependencies and a simple, mobile design.

    Keeping methods small and making them static is the best way of reuse.



    I agree with keeping them small, and would apply the same heuristic to classes.

    I still don't understand what making them static buys you, though. It certainly isn't much simpler to say

    Foo.doSomething()

    than to say

    new Foo().doSomething()

    The latter, though, has an important advantage: it allows us to decouple the "what" (doSomething) from the "how" (implementation of Foo), for example by instantiating Foo at a different place.


    Keap it simple.



    Yes! And don't forget that "simple" doesn't necessarily mean "what's currently the easiest to me" or even "what I'm used to"...
    [ December 29, 2004: Message edited by: Ilja Preuss ]
     
    Gerald Davis
    Ranch Hand
    Posts: 872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Ilja Preuss:
    [QB]
    I still don't understand what making them static buys you, though. It certainly isn't much simpler to say

    Foo.doSomething()

    than to say

    new Foo().doSomething()

    The latter, though, has an important advantage: it allows us to decouple the "what" (doSomething) from the "how" (implementation of Foo), for example by instantiating Foo at a different place.

    [QB]



    How about

    doSomething() //a form of static method called a function.

    It is a prime example of decoupling "what" from the "how" ,no?
    doSomething() function can implement one or many classes without the end user ever knowing about it.
     
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Actually the separation of what and how is best done through abstractions, such as interfaces and abstract classes.

    is good separation. This code knows what will be done - whatever is promised by the interface IFoo - but it has no idea how it is done or even what class will be doing it.

    A static call Foo.doSomething() knows exactly what class is responsible for doing something so what and how are tightly bound. It is hard to replace or extend Foo to do something different because what and how are both present in one place.

    Of course it is possible to write Foo so that it uses another configurable object to do the real work. Then you're just using the static method as syntactic sugar (less typing) and putting the good polymorphic design behind it. I recently had a good experience with this ... a class with all static methods turned out to have a hidden implementation object that I could swap out.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Gerald Davis:
    How about

    doSomething() //a form of static method called a function.

    It is a prime example of decoupling "what" from the "how" ,no?

    doSomething() function can implement one or many classes without the end user ever knowing about it.



    I don't understand what you mean by "can implement one or many classes". The way I understand static methods, you can't swap their implementation, at least not at runtime (and in Java).

    Could you please elaborate?
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Stan James:

    A static call Foo.doSomething() knows exactly what class is responsible for doing something so what and how are tightly bound. It is hard to replace or extend Foo to do something different because what and how are both present in one place.

    Exactly the same argument applies to constructors, which are required to use nonstatic methods. In your example, a call to:



    is just as bound to the MyThing class as



    would be, and the static version has the advantage of being clearer and more efficient.

    Where nonstatic methods are advantageous is when the same bundle of data will be retained for multiple operations, especially when those multiple operations will be invoked in different places in the code.



    rather than



    I think there's a place for both static and nonstatic methods. If you're dealing with an integer object, you want to be able to say "integerObject.toString()", but if you're dealing with a primitive integer, it's better to be able to skip boxing it, instead saying, "Integer.toString(intValue)".

    By the way, I think some of the java.util.Collections functions illustrate how static methods can actually reduce coupling rather than increasing it. For example, by having the static synchronizedMap() method, any new Map subclass can automatically be synchronized. This makes it easier, not harder, to switch to a new Map subclass, because you don't have to worry about modifying the implementation of the new Map subclass to make it synchronized.
    [ December 30, 2004: Message edited by: Warren Dew ]
     
    Stan James
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Yes, creational coupling can be a concern. If we dig back through the archive there was a reference to a neat blog - maybe Martin Fowler or Micah? - about deciding when it's worth to decouple creation through a factory. He suggested you might hide all constructors and always have a static getInstance method that returns a new instance of the same class ... for now. If you ever needed to change exactly what class is being created to some subclass, you could make the change in exactly one spot. To say that is overkill is to say you don't worry about the coupling.

    The risk with static methods is that it is hard to override or replace them. If you believe the class is stable enough that you can live with the risk then static methods are great.

    I like to move creational decisions to configuration. For a couple apps I have have an application assembler that reads the configuration and loads up factories and caches with the implementation class de jur. The assembler itself is a rat's nest of dependencies, but there is only one. In the app that pays my salary we can reload the assembler without stopping and starting the system. Pretty kool.
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Stan James:

    Yes, creational coupling can be a concern. If we dig back through the archive there was a reference to a neat blog - maybe Martin Fowler or Micah? - about deciding when it's worth to decouple creation through a factory. He suggested you might hide all constructors and always have a static getInstance method

    Indeed. And now we are back to using a static method!

    that returns a new instance of the same class ... for now. If you ever needed to change exactly what class is being created to some subclass, you could make the change in exactly one spot. To say that is overkill is to say you don't worry about the coupling.

    In multithreaded applications, I do just that. There's an extra reason for it, though - it's because code in Java constructors can't be synchronized and thus may never appear executed to other threads; a factory method allows initialization to occur outside the constructor safely.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Warren Dew:
    Exactly the same argument applies to constructors, which are required to use nonstatic methods. In your example, a call to:



    is just as bound to the MyThing class as



    would be, and the static version has the advantage of being clearer and more efficient.



    Well, it isn't more clear to me - it's probably more a matter of taste, a matter of what you are used to. And regarding efficiency, I believe that we can safely ignore the difference in most cases.

    The advantage of the former approach is that it allows you to separate instantiation from execution - or as Stan said, when you program to an interface instead of a concrete implementation.

    BTW, what do you think about Gerald's notion that a static method is more reusable? I'd really like to understand where that is coming from...


    I think there's a place for both static and nonstatic methods.



    Well, yes and no. Smalltalk, for example, doesn't have this concept. It *has* class level methods, but they are polymorphic, too!

    If you're dealing with an integer object, you want to be able to say "integerObject.toString()", but if you're dealing with a primitive integer, it's better to be able to skip boxing it, instead saying, "Integer.toString(intValue)".



    Well, yes, but the whole existence of primitives is quite unnecessary, in my humble opinion.

    By the way, I think some of the java.util.Collections functions illustrate how static methods can actually reduce coupling rather than increasing it. For example, by having the static synchronizedMap() method, any new Map subclass can automatically be synchronized. This makes it easier, not harder, to switch to a new Map subclass, because you don't have to worry about modifying the implementation of the new Map subclass to make it synchronized.



    That's a false dichotomy.

    If you take a look at the implemenation of that method, you will actually see that it's just a convenience method for saying

    new SynchronizedMap(myMap)

    which is an implementation of the Decorator design pattern.
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Regarding:

    (new MyThing(aFoo)).doSomething();

    versus

    MyThing.dosomething(aFoo);

    Ilja Preuss:

    Well, it isn't more clear to me - it's probably more a matter of taste, a matter of what you are used to.

    It's not just a matter of taste. Java has beeen my primary language long enough that I write and read the former more than the latter, and I still find the latter clearer.

    I believe that's because the former introduces an extraneous concept: the "new" in the former implies there's memory being allocated and an object being created, which is entirely unrelated to what we are trying to do. The new object, which is never again used, is junk - and it's not just syntactic junk, it's semantic junk. I don't like junk in my code.

    You might have gotten so used to it that you subconsciously ignore the fact that an object is being created - so in that sense, it might be a matter of getting used to it - but it would be better if one didn't have to get used to it in the first place.

    The advantage of the former approach is that it allows you to separate instantiation from execution

    I agree in cases where you actually want to instantiate an object. My fundamental argument is that the latter is preferred when conceptually, one doesn't want to instantiate an object at all. Having no instantiation at all makes execution even cleaner than allowing execution to proceed separately from instantiation.

    or as Stan said, when you program to an interface instead of a concrete implementation.

    As I've demonstrated in my responses to Stan, in Java you always end up programming to a concrete implementation one way or another.

    Even if you use reflection to determine the concrete class from a string in a noncode configuration file, that just moves the difficulty from the code to a configuration file. While this makes things easier for the programmers, I'm far from sure that the accompanying complexity for the release team is worth it - or rather, I think it's worth it in some cases, including from what I can tell the situation Stan is in at work, but I don't think that includes all, or even most, situations.

    I think that the agile concept of not programming for needs that haven't happened - and may never happen - is relevant here. I think it's a waste of time to worry about polymorphism that one may never need. It's better to refactor the code later to account for it when - and if - it's actually needed.

    The whole "programming to an interface" is a bit of a red herring, anyway. All public methods with private implementations - that is, all public methods in Java - are interfaces, even if they aren't part of Java "Interfaces"; arbitrary static methods can dispatch to implementations determined at runtime from a configuration file just as Stan suggests for factory functions.

    BTW, what do you think about Gerald's notion that a static method is more reusable? I'd really like to understand where that is coming from...

    I agree that this is true in some cases. It seems to me that Gerald thinks it's always true - correct me if I'm wrong, Gerald - and I disagree with that. For now, let me focus on the cases where I agree with him, even though they in my opinion a minority.

    To me, the idea is that there are some cases where a method is naturally associated with a particular class, but where one wants to use it without the conceptual overhead of creating an object of that class. For example, suppose I'm putting together a string, and I want to get the line separator character appropriate to the system I'm on. I think it's conceptually simpler to call a static method like System.getProperty("line.separator") than to worry about instantiating an appropriate System object for the system I'm on. It's a simple task - I just want a "\n" or "\r" or some combination - I shouldn't have to worry about all the complexities I'd undoubtedly need to worry about if I had to construct a System object. I don't think I should even have to worry about whether System objects exist - I don't think it would be an improvement to have to call System.getInstance().getProperty("line.separator").

    What does this have to do with reusability? If I can just invoke a quickie static method, I'm likely to use it. If I have to go to the trouble of constructing a potentially complex object - in this case, a System object, or even a Properties object - it's more likely to be quicker for me to write my own method instead of reusing the one that already exists.

    Now, I do think it might be convenient for some projects to be able to instantiate a System object for a system other than one's target, so that, for example, I could make sure I'm writing Windows compatible files even though I'm running on Unix. However, I don't think this implies that everyone should have to worry about this overhead just because a few people might find it convenient.

    Well, yes, but the whole existence of primitives is quite unnecessary, in my humble opinion.

    I agree some of the arguments would change in a language without primitives. I do think, though, that there's a reason such languages haven't made the mainstream, at least not yet.

    That's a false dichotomy.

    If you take a look at the implemenation of that method, you will actually see that it's just a convenience method for saying

    new SynchronizedMap(myMap)


    Er, it's not a false dichotomy at all - convenience is exactly the dichotomy I'm talking about. It's a convenience method because it's more convenient - which means it takes less of my time to write, and more importantly, less of my time to understand when I'm reading the code, because I don't have to worry about irrelevancies like whether a new object is being created.

    Compare how cleanly this works with Java collections, which use the static method approach, with the java.io package, where you have to use straight wrapper classes. Because the java.io package was never organized rigorously enough to put together a set of static convenience methods like the Collections class, you have weird anomalies like having to use BufferedReader to read lines, even though a BufferedWriter won't write lines; you need a PrintStream - from an entirely separate inheritance hierarchy - for that!

    [edited to clarify the answer regarding ease of reuse of static methods]
    [ December 31, 2004: Message edited by: Warren Dew ]
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I just want to add one thing regarding the convenience dichotomy and whether it's false.

    All of object oriented programming is, at its heart, a convenience thing. Being able to write:



    is really just a convenience notation for the equivalent static notation,



    Nonetheless, I think that the former is, in most cases, more convenient - specifically, more convenient to read, because it makes more clear the association between the method implementation being called and the concrete type of the object.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Warren Dew:
    It's not just a matter of taste. Java has beeen my primary language long enough that I write and read the former more than the latter, and I still find the latter clearer.

    I believe that's because the former introduces an extraneous concept: the "new" in the former implies there's memory being allocated



    Well, I actually don't think in terms of memory allocation when I write an algorithm. (I do so, of course, when optimizing memory usage, but that's a quite different state of mind for me.)

    and an object being created, which is entirely unrelated to what we are trying to do. The new object, which is never again used, is junk - and it's not just syntactic junk, it's semantic junk.



    And that's where we differ. It's quite natural to me, as an OO developer, that when I want something done, I need an object that does it for me.

    You might have gotten so used to it that you subconsciously ignore the fact that an object is being created - so in that sense, it might be a matter of getting used to it - but it would be better if one didn't have to get used to it in the first place.



    No, that's not what happened. Actually I'm quite aware of the creation of the object, and in most situations prefer it that way.

    I'm most often working on code that is half a decade old, and contains static methods at many places. Often these cause serious trouble when we try to extend the functionality of the system.

    I agree in cases where you actually want to instantiate an object. My fundamental argument is that the latter is preferred when conceptually, one doesn't want to instantiate an object at all. Having no instantiation at all makes execution even cleaner than allowing execution to proceed separately from instantiation.



    Well, the argument that it is preferred not instanciate an object when "conceptually, one doesn't want to instantiate an object at all" is quite tautological, isn't it?

    The question is, when doesn't one want to? Perhaps a concrete example would help; one that doesn't involve primitives or Creation Methods/Constructors (as we already agree that we need non-instance methods here).

    As I've demonstrated in my responses to Stan, in Java you always end up programming to a concrete implementation one way or another.



    If you refer to some code needing to call a constructor, you are right. *Most* of your code, though, even whole classes, can be written in a way that it doesn't care about concrete implementations at all. And I prefer my code that way.

    I think that the agile concept of not programming for needs that haven't happened - and may never happen - is relevant here.



    That's a tough topic. Agile software development heavily relies on the mobility of the code - it needs to be cheap to change the code. OO principles like the Open Closed Principle and the Dependency Inversion Principle are vital for this. Robert C. Martin's book on the topic discusses those things at great length.

    It's also interesting to see that the Agile movement has its roots in the Smalltalk community, which is one of the oldest, and arguably most powerful OO languages. A lot of people wonder wether without OO techniques the Agile movement would have been possible at all...


    I think it's a waste of time to worry about polymorphism that one may never need. It's better to refactor the code later to account for it when - and if - it's actually needed.



    To me, in it's simplest form, the cost of polymorphism is low enough that it's almost always worth it. Of course you can go over the top - there have been teams that ended up having Factories for Factories for Factories for every single business class, which is without question overkill.

    So we need to find our balances. Seems as if we currently differ on where that balance is for us...

    arbitrary static methods can dispatch to implementations determined at runtime from a configuration file just as Stan suggests for factory functions.



    Well, yes, but is that simpler than doing it the more direct way???

    I don't think it would be an improvement to have to call System.getInstance().getProperty("line.separator").



    Well, yes, that I can agree with. I just find that I don't often write those kinds of methods. Actually I can't remember when I last needed to know the line.seperator property in my code - it's at a level of abstraction I don't have to mess with that often.

    What does this have to do with reusability? If I can just invoke a quickie static method, I'm likely to use it. If I have to go to the trouble of constructing a potentially complex object - in this case, a System object, or even a Properties object - it's more likely to be quicker for me to write my own method instead of reusing the one that already exists.



    I don't buy that. If at all, I would write a method that delegated to the original one, which certainly would count as reuse?

    I agree some of the arguments would change in a language without primitives. I do think, though, that there's a reason such languages haven't made the mainstream, at least not yet.



    Certainly. The two main reasons for Java becoming mainstream, for example, were that it looked a lot like C/C++, and that you could develop applets.

    I don't know enough about the history of Smalltalk to really comment, but I doubt that it were mostly language design reasons that made it not become mainstream.

    Er, it's not a false dichotomy at all



    You seemed to imply to me that you either needed to subclass every Map implementation, or have the static method to get a Map synchronized. That looked like a false dichotomy to me, as you ignored at least one third option in your argument. http://c2.com/cgi/wiki?FalseDichotomy

    Compare how cleanly this works with Java collections, which use the static method approach, with the java.io package, where you have to use straight wrapper classes. Because the java.io package was never organized rigorously enough to put together a set of static convenience methods like the Collections class, you have weird anomalies like having to use BufferedReader to read lines, even though a BufferedWriter won't write lines; you need a PrintStream - from an entirely separate inheritance hierarchy - for that!



    I agree that the latter design is confusing, but I don't understand at all how static methods would change that. It certainly wouldn't be hard to come up with a better design without using static methods. (In fact, even if you'd provide static convenience methods, you'd first have to correct the class design anyway, as the static methods needed to make use of it.)
    [ January 02, 2005: Message edited by: Ilja Preuss ]
     
    Pho Tek
    Ranch Hand
    Posts: 782
    Python Chrome Ubuntu
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ilja,


    To me, in it's simplest form, the cost of polymorphism is low enough that it's almost always worth it. Of course you can go over the top - there have been teams that ended up having Factories for Factories for Factories for every single business class, which is without question overkill.


    Eric Evans, the author of DomainDrivenDesign has good advices on when to use factories and when to use plain constructors. A snip:


    Constructors should be dead simple. Complex assemblies, especially AGGREGATES, call for FACTORIES.


    Of course I think dependency injection style of assembly (aka what Stan James did) is the way of the future for object creational needs.
     
    Gerald Davis
    Ranch Hand
    Posts: 872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I told me that static methods are good then I found this website. http://www.javaworld.com/javaworld/javatips/jw-javatip107.html

    ��new� in the former implies there's memory being allocated and an object being created, which is entirely unrelated to what we are trying to do�

    I consider �new� command to be a low-level command and should be treated as such .Imagine how awkward it would be if calculus, music notation, formal method even SQL(to a limited extent) was object oriented. Imagine using Electrodynamics in anything other then relativistic notation.

    Sometime we need the help of domain experts in our project, but most of those experts don�t know anything about object orientation, but object orientated technology seems to be mixed with domain specific things.

    2+2 or any complicated mathematics we don�t want to think allocating memory we want to get a job done and any notion of allocating memory should be hidden away.

    In some Systems for example like airline booking system, there are object entities like Customers, Planes and airline companys. Isn�t the other functionality just static processes that just work on these objects to change, create or remove them. Yes, some static processes might require the explicate use of object initiation to work but unless they are to do with the business domain objects (in this example Customer, Plane and airline Company) I would see those processes are badly designed.


    Object allocation and other low-level functionality should be the domain of reusable libraries, frameworks and toolkits who might use low-level languages like C++ or Java, not application construction experts whose only interest is to bind these libraries together to build the final application.

    EJB is a prime example of this, the only object that explicitly created are domain object the rest is taken care for you by the container. If the clients side was implemented in a high level language like VB or Python you would not have to explicitly manage any none domain specific object.

    The advantages are clear: The EJB container and the high-level languages implementation could change and improve without effecting the domains specific code.

    Python: Cuts through the crap , no distraction.



    Java: Should there be ever a better IO library to be implemented in the next version of Java it would be very hard to do because the interface between the domain specific code(your code) and the language is so complicated.


    I probably repeating myself again but maybe that is because what I say always comeback to the same simple concepts.
     
    Stan James
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    It all gets down to what's important to you. If you own all the code and you're willing to refactor changes throughout the baseline you can be perfectly happy with scripting languages or Java solutions with fewer moving parts.

    If you want to have "closed" components - perhaps you sell a jar with no source or you work with a jar from another team or you'd rather not build, test and deploy certain bits of your application - you will find value in the more intricate solutions.

    Building my Wiki I'm in the former category - I own all the code, I build it all together into one jar, and I can live with the refactoring required if changing one class breaks another. But I write it in the latter style for good practice and because it does make my life easier. At work I'm deep in the latter category!

    I avoided calling the two approaches "simple" or "complex". The number of lines of code or source tokens or classes is a poor measure of simplicity beyond typing. The Simplest Thing That Can Possibly Work must first of all WORK, satisfying all kinds of requirements. And it must support you through the life of the code. Code that is simple to write is not necessarily simple to maintain or modify.
     
    Ilja Preuss
    author
    Posts: 14112
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Gerald Davis:
    I told me that static methods are good then I found this website. http://www.javaworld.com/javaworld/javatips/jw-javatip107.html



    Let's take a look at the reasons given for not using instance methods:

    - Class inheritance is a suboptimal mechanism for code reuse due to its lack of precision.

    Well, inheritance is not the only way to reuse instance methods, there is also composition.

    - changes made to the parent class can break the subclass

    We can generalize that statement to "changes can break the system". Therefore you should have tests for your system, so that you notice when you break something.

    - when modifying either class, it can be difficult to remember which methods are or are not overridden

    I don't need to remember that - my IDE is showing me that at a fingertip. Also I typically think of *all* non-private methods as potentially being overridden. If I don't want them to, I make them final. (The latter is also an effective way to find out wether one is overridden - you get a compile error if it is.)

    - it can be unclear whether or not an overridden method should call the corresponding parent method

    With all due respect, if you don't understand the code you are working on (and don't have the safety net of tests), you probably shouldn't change it, anyway.

    For methods that *need* to be overridden *and* called from the overriding methods, it's typically more save to use the Template Method pattern.

    So I guess I simply don't see the problem the first step of the article tries to solve. I can't remember one incident in my programmig career where I think the presented solution would have been beneficial. The other two steps I can agree with, though.

    I consider �new� command to be a low-level command and should be treated as such.



    Why? Doesn't it just mean that a new object gets created?

    Imagine how awkward it would be if calculus, music notation, formal method even SQL(to a limited extent) was object oriented. Imagine using Electrodynamics in anything other then relativistic notation.



    Sorry, can't even imagine what you mean by "music notation" being "object oriented", or what things about software development we could conclude from it being akward. I do know persistence layers, though, that present an object oriented facade to SQL, and think of them as being quite elegant (Toplink comes to mind).

    Sometime we need the help of domain experts in our project, but most of those experts don�t know anything about object orientation, but object orientated technology seems to be mixed with domain specific things.



    Well, I never was a fan of "OOA". The domain experts should explain the domain to me in words we both understand, and tell me what the system should do. Then I decide how to structure the system so that they get what they need in a way that it later is easy to maintain and extend by me and other developers. In don't think that the latter structure necessarily needs to be fully understandable to the domain experts.

    2+2 or any complicated mathematics we don�t want to think allocating memory we want to get a job done and any notion of allocating memory should be hidden away.



    Interestingly, in Smalltalk, "2 + 2" creates an instance of (if I remember correctly) SmallInteger with the value '2' and calls the method '+' on it with the argument of another SmallInteger. Java does something similar with String literals. So to me that's not an argument for non-OO code at all.

    Actually this shows the power of OO code: You can actually write your own Integer implementation and it will automatically work with all the client code that uses Integers, without any changes.

    In some Systems for example like airline booking system, there are object entities like Customers, Planes and airline companys. Isn�t the other functionality just static processes that just work on these objects to change, create or remove them.



    I don't know what you mean by "static" here. I'm quite sure that that meaning of "static" has nothing at all to do with the "static" keyword.

    More importantly, they are typically not static in the sense that they typically change over time, that is the software system needs to be adapted to a changed business process (most often actually the whole goal of introducing a new software system is to change the business process, else the software would be worthless). And that adaption is the easier the better decoupled the software is. And OO techniques are under the most powerfull techniques for decoupling software entities.

    Yes, some static processes might require the explicate use of object initiation to work but unless they are to do with the business domain objects (in this example Customer, Plane and airline Company) I would see those processes are badly designed.



    What, for you, is the goal of a good design?


    Object allocation and other low-level functionality should be the domain of reusable libraries, frameworks and toolkits who might use low-level languages like C++ or Java, not application construction experts whose only interest is to bind these libraries together to build the final application.



    I somehow can't connect to this vision of how work should be divided between roles. Are you acually working that way? Can you tell us a little bit more?

    The advantages are clear: The EJB container and the high-level languages implementation could change and improve without effecting the domains specific code.



    Well, I guess that the JVM's implementation of "new" has changed from JDK to JDK, too.

    Python: Cuts through the crap , no distraction.



    Well, your comparision to the Java code seems to be a little bit unfair, as the python version doesn't seem to contain error handling code at all.

    Without question is Python an interesting language. As you might have noticed, both write() and close() are instance methods that are called polymorphically in your example.

    And in Java 5 it wouldn't be too much effort to write your own static method and Range class so that you could write quite similar code (not fully similar, as Java is manifestly typed, whereas Python is implicitely typed):

     
    Stan James
    (instanceof Sidekick)
    Posts: 8791
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    I broke down and read that article. I keep thinking that people who really want to write in C should just write in C and leave off trying to get the rest of us to write C in Java.

    His reading of GoF seems suspect. Strategy is about alternative behaviors for the same interface, not an interface per set of methods. Flyweight is about shared state, not shared behavior in stateless objects. He uses Flyweight to have a "single well-known instance" of each class, which is nearly word for word from Singleton.
     
    Warren Dew
    blacksmith
    Posts: 1332
    2
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator
    Ilja Preuss:

    The question is, when doesn't one want to? Perhaps a concrete example would help ...

    Given you've agreed with all my examples so far, I'm not sure we're really that far apart.

    Still, let me provide one more example. I was working today on an abstract "command line application" superclass that's going to be used in several applications that I and a couple of other guys are porting. The original MSVC++ code uses sprintf() variations extensively, so I had written a few utility functions that allowed the use of some of the formatting strings that C supports (we're not using 1.5 where these libraries are supplied automatically).

    While writing a test for this abstract class, I realized that these utility functions don't use any member data, so they could be made static. I did so, because that will allow code that's not in a subclass of this abstract class to more easily reuse these functions. (It also makes it easier to move these functions to a more general utility class if and when that becomes worth the effort.)

    Now, I could theoretically have gone with a more object oriented design similar to the java.util.regex package, perhaps requiring the user to construct a Format object on the format string and use a member function to get the resulting formatted string. However, this would have required several times as much work on my part - and, in my opinion, would have made these utilities more difficult, not easier, for others to reuse.

    Now, I'm not saying to make everything static - far from it. Probably 80% of the code I write is in nonstatic functions. And while I sympathize with the first paragraph of the article Gerald provided, I think the example provided in that article goes a long way towards disproving the author's point - I can't imagine a situation where static functions are less appropriate. I just think that the other 20% - maybe a smaller percentage for you - does still exist, and that it often includes the code that's most likely to be reused.

    [regarding java.io]

    In fact, even if you'd provide static convenience methods, you'd first have to correct the class design anyway, as the static methods needed to make use of it.

    That was pretty much my point. If the authors of that package had troubled to think about how to provide static convenience methods, they would have been forced to clean up the class design.
     
    Gerald Davis
    Ranch Hand
    Posts: 872
    • Mark post as helpful
    • send pies
      Number of slices to send:
      Optional 'thank-you' note:
    • Quote
    • Report post to moderator

    Originally posted by Ilja Preuss:

    And in Java 5 it wouldn't be too much effort to write your own static method and Range class so that you could write quite similar code (not fully similar, as Java is manifestly typed, whereas Python is implicitly typed):



    I guess you are correct, but it would then be your reusability to optimize it, debug it, test it, document it, and to make sure it is compatible with next version of java. Put with Python you have a whole team of python developer to do this on your behalf.

    Originally posted by Ilja Preuss:

    I somehow can't connect to this vision of how work should be divided between roles. Are you acually working that way? Can you tell us a little bit more?


    For me, it comes out of not wanting to reinvent the weal. I prefer to spend my time looking for libraries that would save me having to code it myself. The role I play is application developer, the implementation of reusable libraries are not my concern.
    Sometime I find native Python libraries; if not, there usually is a C/C++ one available.

    Originally posted by Ilja Preuss:

    What, for you, is the goal of a good design?


    Simplicity and Data hiding
    These come about by using a high-level language with high-level library. Functionality should not maintain state unless it really needs to. This way they can never get into an inconsistent state which can happen if end-user-developer doesn�t know how to use the object or while using multi-threading and trying to maintain the state of loads of object floating around in the system.

    Functionality should have one entry and one exit point if possible, this make it easier to understand and use.

    EJB good design practice might be of help to you to understand better, even though I am not a fan of EJB, it promotes much of what I have said. Read about the benefits of Stateless Session beans. The last time I learned about EJB they promoted the use of Stateless Beans whenever possible especially using them as a fa�ade they even hide domain specific object away from client only use strings and integer Id to modify them, so those objects can be redesigned without effecting client code.

    The GUI wxWidget even uses ID to manipulate references for its GUI components, maybe that is one of the reasons way wxWidget does a good job of hiding the underlying implementation. There is already a Gtk ,X11 and WFC implementation maybe Swing and TCL will be next.



    Originally posted by Ilja Preuss:

    Interestingly, in Smalltalk, "2 + 2" creates an instance of (if I remember correctly) SmallInteger with the value '2' and calls the method '+' on it with the argument of another SmallInteger.


    Wouldn�t this have implication if you need to use complexes algebra, wouldn�t the use of parenthesis or algorithm precedence be effected, I have a gut feeling that it does but not completely sure.

    Originally posted by Ilja Preuss:

    I do know persistence layers, though, that present an object oriented facade to SQL, and think of them as being quite elegant (Toplink comes to mind).



    I guess you could be correct, that�s because SQL is not a very nice language it is hard to break down into manageable chunks and Object Orientation can be better at handling data. But for those notations that do their job well like algebra, I don�t want to see any �new� or method declereations mixed in with the notation.
     
    Yes, of course, and I accept that blame. In fact, i covet that blame. As does this tiny ad:
    Gift giving made easy with the permaculture playing cards
    https://coderanch.com/t/777758/Gift-giving-easy-permaculture-playing
    reply
      Bookmark Topic Watch Topic
    • New Topic