使用实用程序生成Java代码,使我的项目更简洁.好主意?

Bob*_*age 3 java android code-generation

我正在进行的项目要求我编写大量重复的代码.例如,如果我想在我的代码中加载一个名为"logo.png"的图像文件,我会写这样的东西:Bitmap logoImage;

...
// Init
logoImage = load("logo.png")

...
// Usage
logoImage.draw(0, 0);

..
// Cleanup
logoImage.release();
Run Code Online (Sandbox Code Playgroud)

必须编写此代码以使用每个新图像是一件痛苦的事情,包括必须指定logoImage应该加载文件"logo.png".

由于我正在开发一个Java Android游戏并且图像在内部循环中被大量使用,我真的想避免做出虚拟函数调用这样的慢速事情,例如当我可以避免它时访问数组/地图/对象字段.从Android API(生成的R类)复制一个想法,我想我可以在编译之前运行一个实用程序来为我生成一些重复的代码.例如,项目文件中的实际代码将简化为:

logoImage.draw(0, 0);
Run Code Online (Sandbox Code Playgroud)

使用一些命令行工具(例如grep,sed),我可以查找"Image.draw(..."的每个实例,然后自动生成其他所需的代码,即加载/释放文件的代码.png并声明"位图logoImage"某处.此代码可以添加到新类中,也可以在我的代码中添加占位符,告诉代码生成器在哪里插入生成的代码.

要显示新图像,我需要做的只是将图像文件复制到正确的目录并添加一行代码.很好,很简单.这避免了创建图像数组,定义标记的int常量以引用数组以及必须指定要加载的文件名等方法.

这是一个非常糟糕的主意吗?这看起来有点像黑客,但我看不到更简单的方法,它似乎彻底清理我的代码.是否有任何标准工具可用于执行此类简单的代码生成(即该工具不需要了解代码的含义)?还有其他人做这样的事情来弥补语言功能吗?

Ste*_*n C 5

使用代码生成这样的事情是个坏主意.(IMO,代码生成应保留用于需要生成大量代码的情况,这听起来不像那种情况.)

如果当前解决方案中的样板代码与您有关,那么实现图像注册表抽象的更好解决方案(而不是代码生成); 例如

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 ...
    }
}
Run Code Online (Sandbox Code Playgroud)

替换logoImage.draw(0, 0)等与:

registry.getImage("logo.png").draw(0, 0);
Run Code Online (Sandbox Code Playgroud)

删除所有load呼叫,并release通过一次呼叫替换所有呼叫registry.shutdown().

编辑以回应OP的评论如下:

...但我提到我正在为手机写游戏.每次我绘制精灵时,HashMap查找都会导致性能下降.

啊......我从另一个线程中记得你.

  1. 您(再次)在没有任何实际性能测量基础的情况下对性能做出假设.具体来说,您假设HashMap查找过于昂贵.我的直觉是,进行查找所花费的时间将是绘制图像所用时间的一小部分(<10%).此时,它正接近用户无法察觉的水平.

  2. 如果您的测量(或直觉)告诉您散列图查找过于昂贵,那么写这个是一个微不足道的修改:

    Image image = registry.getImage("logo.png"); while(...){... image.draw(0,0); }


例如,Google甚至建议您不要在内部循环中使用迭代器,因为这会导致在释放Iterator对象时触发GC.

这是无关紧要和不准确的.

  1. 使用String键的HashMap查找不会生成垃圾.永远不会.

  2. 在内部循环中使用迭代器不会"在释放Iterator对象时导致GC触发".在Java中,您不释放对象.这就是C/C++的思考.

  3. 在内部循环中实例化迭代器会执行new一个对象,但只有在new操作达到内存阈值时才会触发GC .这种情况偶尔发生.


此外,写入"file_that_does_not_exist.png"将不会被您的示例选为编译时错误.

您的原始解决方案或代码生成方法都不会为丢失的文件提供编译时错误.