Using a utility to generate Java code to make my project more concise. Good idea?
The project I'm working on requires me to write lots of repetitive code. For example, if I want to load a image file called "logo.png" in my code, I would write something like this: Bitmap logoImage;
...
// Init
logoImage = load("logo.png")
...
// Usage
logoImage.draw(0, 0);
..
// Cleanup
logoImage.release();
Having to write this code to use every new image is a pain, including having to specify that logoImage should load the file "logo.开发者_运维知识库png".
As I'm working on a Java Android game and images are used a lot in inner loops, I really want to avoid slow things like making virtual function calls and e.g. accessing arrays/maps/object fields when I can avoid it. Copying an idea from the Android API (the generated R class), I thought I could run a utility before compiling to generate some of this repetitive code for me. For example, the actual code in the project file would be reduced to just this:
logoImage.draw(0, 0);
Using some command-line tools (e.g. grep, sed), I can look for every instance of "Image.draw(..." and then generate the other required code automatically i.e. code to load/release the file .png and declare "Bitmap logoImage" somewhere. This code could either be added to a new class or I could add placeholders in my code that told the code generator where to insert the generated code.
To display a new image, all I would need to do is just copy the image file to the right directory and add one line of code. Nice and simple. This avoid approaches like creating an array of images, defining labelled int constants to references the array and having to specify which filename to load.
Is this a really bad idea? It seems a bit of a hack but I can see no easier way of doing this and it does seem to drastically clean up my code. Are there any standard tools for doing this simple kind of code generation (i.e. the tool doesn't need to understand the meaning of the code)? Does anyone else do things like this to make up for language features?
It would be a bad idea to use code generation for something like this. (IMO, code generation should be reserved for situations where you need to generate vast amounts of code, and this doesn't sound like that situation.)
If the boilerplate code in your current solution concerns you, a better solution (than code generation) is to implement an image registry abstraction; e.g.
public class ImageRegistry {
private Map<String, Image> map = new HashMap<String, Image>();
public synchronized Image getImage(String filename) {
Image image = map.get(filename);
if (image == null) {
image = load(filename);
map.put(filename, image);
}
return image;
}
public synchronized void shutdown() {
for (Image image : map.valueSet()) {
image.release();
}
map.clear(); // probably redundant ...
}
}
Replace logoImage.draw(0, 0)
and the like with:
registry.getImage("logo.png").draw(0, 0);
remove all of the load
calls, and replace all of the release
calls with a single call to registry.shutdown()
.
EDIT in response to the OP's comments below:
... but I mention that I'm writing a game for a phone. A HashMap lookup every time I'm drawing a sprite will kill performance.
Ah ... I remember you from another thread.
You are (yet again) making assumptions about performance without any basis in actual performance measurements. Specifically, you are assuming that HashMap lookup is going to be too expensive. My gut feeling is that the time taken to do the lookup will be a small percentage ( < 10% ) of the time taken to draw the image. At that point, it is approaching the level at which it is unnoticable to users.
If your measurements (or gut feeling) tells you that a hashmap lookup is too expensive, it is a trivial modification to write this:
Image image = registry.getImage("logo.png"); while (...) { ... image.draw(0, 0); }
For example, Google even go as far as to recommend you don't use iterators in inner loops because these cause the GC to fire when the Iterator objects are deallocated.
That is irrelevant and inaccurate.
A HashMap lookup using a String key does not generate garbage. Not ever.
Using an iterator in an inner loop does not "cause the GC to fire when the Iterator objects are deallocated". In Java, you don't deallocate objects. That is C/C++ thinking.
Instantiating an iterator in an inner loop does
new
an object, but the GC will only fire if thenew
operation hits the memory threshold. This happens only occasionally.
Also, writing "file_that_does_not_exist.png" will not be picked up as a compile time error with your example.
Neither your original solution, or the code generation approach can give you a compile time error for a missing file either.
Avoid code-generation. It often makes code hard to maintain.
In your case why don't you just make:
public class ImageUtils {
public static void drawAndRelease(String name) {
logoImage = load(name)
logoImage.draw(0, 0);
logoImage.release();
}
}
and then just call:
ImageUtils.drawAndRelease("logo.png");
If there is more code between these methods - well, then they are atomic methods and you won't know where to put them in case you use code-generation.
I second Bozho's answer about avoiding code generation, but if you have to write repeatable snippets of code, any good IDE usually has some built in support for specifying your own snippets with variables and everything. IntelliJ IDEA has this feature, it's called Live Templates. I would guess both Eclipse and NetBeans has similar functionality.
You transfer complexity to code generation, and it (generation) is not trivial and may be buggy. Code is harder to read and maintain. Some clear rules to design and coding are more helpful here.
Several ways:
Eclipse code2code, you cod in template using template language such as FreeMarker, groovy, etc
eclipse sqLite plugin for Android autogenerates sqlite code
MotoDevStudio4android has code snippets which yo could use
精彩评论