Win a copy of TDD for a Shopping Website LiveProject this week in the Testing forum!
  • 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
  • Paul Clapham
  • Ron McLeod
  • Jeanne Boyarsky
  • Tim Cooke
Sheriffs:
  • Liutauras Vilda
  • paul wheaton
  • Henry Wong
Saloon Keepers:
  • Tim Moores
  • Tim Holloway
  • Stephan van Hulst
  • Carey Brown
  • Frits Walraven
Bartenders:
  • Piet Souris
  • Himai Minh

CodeGenerator code refactoring

 
Ranch Hand
Posts: 162
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hello.

I�ve got this code:

and I need to do refactoring. The main idea is: number of languages may grow.

So, I decide to use Strategy pattern and made it like this:


Now, the question: Is there a better way for refactoring of that code? Any ideas? :roll:

Thanks, George.
 
author and iconoclast
Posts: 24204
44
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
That's definitely the direction to go. It's generally a good idea to program to interfaces when you can, so I'd make CodeGenerator an interface, and if the present CodeGenerator class has useful methods the other Generators use, then make that into a default implementation class CodeGeneratorImpl.

I notice you've made your implementation classes non-public, which is good; you probably want a Factory class to create instances.
 
Georgy Bolyuba
Ranch Hand
Posts: 162
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator


That's definitely the direction to go. It's generally a good idea to program to interfaces when you can, so I'd make CodeGenerator an interface, and if the present CodeGenerator class has useful methods the other Generators use, then make that into a default implementation class CodeGeneratorImpl.



Hum� Can you put more light on �It's generally a good idea to program to interfaces when you can�? Why it�s so? It looks like generating of code is the main goal of subclasses of CodeGenerator.


I notice you've made your implementation classes non-public, which is good; you probably want a Factory class to create instances.



I was thinking about using Factory pattern, but� Let look closer to the constructor of CodeGenerator before refactoring. It has default (package) access level and has language id as a parameter. So, I make a conclusion that client should know which language it wants. And Factory usually is used to produce objects when client code shouldn�t know exactly object of what class it gets.

Look here (client code):


I mean in this case Factory patter could be not necessary. But, we cannot say it for sure cause of lack of information.

Anyway, thanks alot, Ernest.
 
(instanceof Sidekick)
Posts: 8791
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
How about after refactoring:

Now factory can have a map of generators so you configure new generators with a properties file or XML or database or whatever ...

The first two lines never change when you add new generators. If you're lucky, the factory never changes when you add new generators. Good Clean Fun!
 
Georgy Bolyuba
Ranch Hand
Posts: 162
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Hi, Stan. Thanks for reply.

As I sad before I was thinking about adding CodeGeneratorFactory class. But I have some doubts.
Lets compare two pieces of code:


For me both pieces of code are equal, cause as I sad before client-code have to choose language explicitly (by providing value if _language or by instancing concrete class). This means that if client-code wants to get code in different language it (client-code) have to be changed. So, using the Factory pattern don�t give us any bonuses, only one more class to code.


If you're lucky, the factory never changes when you add new generators.


And if I have no factory it will never change, that�s for sure.

Thanks again for your reply.
George.
 
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
There are a few differences between 1 & 2, and they may or may not matter to you.

The class that has the code in example one has no dependencies on any language generator. You can compile it without having written any generators. You can also plug in new generators without compiling and distributing it again. Kind of the way you can add new plugins to Eclipse without having to compile Eclipse.

We often call this "closed" for modification but "open" for extension. This tends to be more important in larger systems where you'd like some modules (bunch of classes) to be stable while others can change. For example my current work project tries to have a stable core that never changes, with new products and user groups that plug in.

I like to increase the number of classes that never change, because every change is an opportunity to make some new kind of mistake.
 
Ernest Friedman-Hill
author and iconoclast
Posts: 24204
44
Mac OS X Eclipse IDE Chrome
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Thanks for jumping in, Stan. I second everything he said with regards to the factory part.

Note that some of the same issues are relevant in the "programming to interfaces" part, and there are more. Because Java has only single inheritance of implementation, anytime you force someone to extend a class, you limit their options. It's always better to use an interface, provide a default base class, but not require its use. What if someone want a Generator with a GUI (perhaps for educational purposes?) and so wants their Generator to be a Component? Well, it can't be both. If you use the interface, you open up that option.

As far as the similar parts: using an interface means you can compile the whole application without the generators. This is great during development, and it's great if any other generators drag in external libraries that increase compile times and complexify builds.

Using an interface makes testing much easier: it's much easier to plug in a mock Generator if the mock doesn't have to extend a concrete class (most if not all of the established "mock objects" testing libraries require that you're mocking an interface.)

And what if CodeGenerator has some member variables which not all subclasses need? That means every subclass has to drag around that extra baggage. If you use an interface, this doesn't happen. I realize that might not be relevant here, but it's an important consideration for the "Programming to interfaces" concept in general.
 
Georgy Bolyuba
Ranch Hand
Posts: 162
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
Stan and Ernest Thanks alot!

This topic has really helped me.

George
 
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
Thanks for sticking with us. Some of these ideas are important in big, complex systems but the value may be hard to see on small, personal projects. I try to practice the best ideas I can come up with all the time so when I hit the big projects I'll have some experience to draw on. Keep hanging out here and see how we do.
 
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In your current application the interface that you have defined may not change in the future. Be aware of the fact that in applications that might require modifications to the interface after you publish them will result in breaking all the clients that implement it.

This is not so in the case of abstract classes. Abstract classes could provide default implementation so that the clients that extend it does not have to implement the new method(s).

So if you want to realize the full potential of interfaces, make sure that the abstraction that you capture in the interface is not likely to change in the future. One of the way to make your interfaces stable is to make the return types Interfaces rather than concrete classes. For example return Collection interface rather than ArrayList class. This allows you to change your data structure to Stack or anything that implements the Collection interface later.

The exception here is that you could return objects that represent key abstraction in the domain that are not likely to change in the future. This is your only choice if you do not have access to the source code (third party libraries, team that is currently working on the implementation for another layer of the system etc).
 
Balachandran Paranjothimani
Ranch Hand
Posts: 43
  • Mark post as helpful
  • send pies
    Number of slices to send:
    Optional 'thank-you' note:
  • Quote
  • Report post to moderator
In your code it is appropriate to throw IllegalArgumentException instead of Exception.

IllegalArgumentException extends RuntimeException and you don't have to declare it in the signature of the method.

This exception is thrown to indicate that a method has been passed an illegal or inappropriate argument.
 
This tiny ad is wafer thin:
Free, earth friendly heat - from the CodeRanch trailboss
https://www.kickstarter.com/projects/paulwheaton/free-heat
reply
    Bookmark Topic Watch Topic
  • New Topic