Java:访问资源和德墨忒耳定律

概述

在我的(Android)Java游戏中,我有一个名为resources的类。顾名思义,此类包含游戏的资源。我所有的OpenGL对象(精灵)都是在这里创建的

它看起来像下面这样(显然,与实际项目中出现的版本相比,这是一个简化的版本):

public class Resources {

    Hero hero;
    Enemy enemy;
    MenuButtons mainMenuButtons;
    Background background;
    Scene mainMenu;

    public void createObjects(){

        hero = new Hero();
        enemy = new Enemy();
        mainMenuButtons = new MenuButtons();
        background = new Background();
        mainMenu = new Scene(this);

    }
}

因此,在我的主菜单场景中,我需要访问我的对象,因此我们可能会看到如下内容:

public class mainMenu implements Scene {

    Resources resources;

    public mainMenu(Resources resources){

        this.resources = resources;

    }

    @Override
    public void render(){

        resources.background.draw();
        resources.hero.draw();
        resources.enemy.draw();
        mainMenuButtons.draw();           

    }

    @Override
    public void updateLogic(){

        resources.hero.move();
        resources.enemy.move();
        resources.mainMenubuttons.animate();
    }

}

现在,上述方法只是访问资源中的对象及其方法的一种方法。但这真的打破了得墨忒耳定律吗?如果没有,为什么不呢?如果是这样,以不违反 LOD 的方式访问这些对象的最佳方式是什么?

访问?

一个选项(我已经排除了TBH - 见下文)是将访问器方法放入我的资源类中。这样我就可以做这样的事情:

resources.drawBackround();

有很多对象,我需要每个对象的每个方法/变量的访问器。不是很实用,似乎我正在编写大量额外的代码,最重要的是,它使资源类变得荒谬地长,因为它充满了这些访问器。因此,我不会走这条路。

将对象传入场景的构造函数

当然,我也可以做这样的事情:

    hero = new Hero();
    enemy = new Enemy();
    mainMenuButtons = new MenuButtons();
    background = new Background();
    mainMenu = new Scene(hero, enemy, mainMenuButtons, background);

所以我可以简单地做到这一点:

    background.draw(); //etc....

这对于简单的场景(例如不需要很多对象的菜单系统)是可行的,但对于主游戏,它可能很快就会变得一团糟,因为我必须将对大约30多个对象的引用传递到构造函数中,这听起来不太对......

因此,如果有人能指出最好的方法和原因,我将不胜感激。


答案 1

因此,如果有人能指出最好的方法和原因,我将不胜感激。

在我看来,最好的方法是保留 Resources 类,将所有对象设为私有,以免违反法律并编写访问器(但不是像您已经排除的那样针对每个对象)。

我有很多对象,我需要每个对象的每个方法/变量的访问器。不是很实用,似乎我正在编写大量额外的代码,最重要的是,它使资源类变得荒谬地长,因为它充满了这些访问器。因此,我不会走这条路。

我假设许多对象属于同一类。因此,您不必为每个对象创建一个访问器,这实际上会炸毁类。我是一个游戏,你通常有一个英雄,一个或多个敌人和许多精灵。

public class Resources {

    private Hero hero;
    private Enemy enemy;
    private MenuButtons mainMenuButtons;
    private Background background;
    private Scene mainMenu;

    public void createObjects(){

        hero = new Hero();
        enemy = new Enemy();
        mainMenuButtons = new MenuButtons();
        background = new Background();
        mainMenu = new Scene(this);

    }

    public Hero getBackground() {

        return background;
    }

    public Hero getHero() {

        return hero;
    }

    public List<Enemy> getEnemies() {

        ArrayList<Enemy> list = new ArrayList<Enemy>();
        list.add(enemy);
        list.add(next_enemy);
        return list;
    }

    public List<Sprite> getSprites() {

        ArrayList<Sprite> list = new ArrayList<Sprite>();
        list.addAll(enemy.getActiveSprites());
        return list;
    }

}

除了 getHero() 和 getEnemy(), 如果 Hero 和 Enemy 派生自同一类,你也可以创建 getActor() 方法。getSprites() 方法只是一个示例。

如果该解决方案对您不起作用,我有另一个建议。

使资源类执行一些工作。

public class ResourceManager {

    private Hero hero;
    private Enemy enemy;
    private MenuButtons mainMenuButtons;
    private Background background;
    private Scene mainMenu;

    public void createObjects(){

        hero = new Hero();
        enemy = new Enemy();
        mainMenuButtons = new MenuButtons();
        background = new Background();
        mainMenu = new Scene(this);

    }

    public void render(Scene scene) {

        this.background.draw();
        if (scene != mainMenu) {

            this.hero.draw();
            this.enemy.draw();
        }
        this.mainMenuButtons.draw();           

    }

    public void updateLogic(Scene scene){

        this.hero.move();
        this.enemy.move();
        this.mainMenubuttons.animate();
    }

}

然后,mainMenu 直接在 RescourceManager 类中调用逻辑方法。

public class mainMenu implements Scene {

    ResourceManager resourceManager;

    public mainMenu(ResourceManager resourceManager){

        this.resourceManager = resourceManager;
    }

    @Override
    public void render(){

        resourceManager.render(this);
    }

    @Override
    public void updateLogic(){

        resourceManager.updateLogic(this);
    }

}

我希望我的建议能帮助你弄清楚如何继续你的项目。


答案 2

您可以使用依赖关系注入并消除资源类。然后,您可以在您的字段上调用函数,并且不会违反德墨忒耳定律。

下面是使用构造函数注入的示例:

public class MainMenu implements Scene {

   Background background;
   Hero hero;  
   Enemy enemy; 
   MenuButtons buttons

    public mainMenu(Background background, Hero hero,  Enemy enemy, MenuButtons buttons){

       this.background = background;
       this.hero = hero;
       this.enemy = enemy;
       this.buttons = buttons;   
    }

    @Override
    public void render(){

        this.background.draw();
        this.hero.draw();
        this.enemy.draw();
        this.mainMenuButtons.draw();           

    }

    @Override
    public void updateLogic(){

        this.hero.move();
        this.enemy.move();
        this.mainMenubuttons.animate();
    }

}

使用依赖注入,您可以将实例传递到构造函数和函数中,而不是在类中“新建”它们。但是,您需要在某个地方管理您的实例,并且有很多库可以为您做到这一点。Dagger是Android上流行的一种:http://square.github.io/dagger/


推荐