【问题标题】:Java: using local vs instance variables?Java:使用本地与实例变量?
【发布时间】:2024-01-22 20:30:01
【问题描述】:

我的应用中有 3 个classes

1. Runner / Main(调用服务类)

2。服务类(执行业务逻辑)

3.存储库类(由服务调用以进行数据库查询)

我不确定在服务类中实现变量的最佳方式。以下 2 种方法中哪种方法最好?为什么

例如我应该有实例变量

public class DogService{

    List<Dogs> dogList= new ArrayList<Dog>(); //instance var

    public DogService(){}

    public List<dogs> getAllDogs(){

    dogList=dogRepository.getAll();

    return dogList;

        }

    }

或方法中的局部变量

public class DogService{

       public DogService(){}

        public List<dogs> getAllDogs(){

       List<Dogs> dogList= new ArrayList<Dog>(); //local var to method

        dogList=dogRepository.getAll();

        return dogList;

            }

        }

服务类使用示例:

public class Runner {

    List<Dogs> listOfAllDogs = new ArrayList<Dog>();

    DogService dogService = new DogService();

    public static void main(String[] args) {

    listOfAllDogs = dogService.getAllDogs();

}

【问题讨论】:

  • 这里没有区别。无论何时调用getAllDogs,该变量都会被覆盖。使用局部变量,直到有理由反对它。
  • 好的,那我为什么要使用本地变量呢?在什么情况下我会使用实例变量?
  • 老实说,这个问题没有实际意义,因为服务层没有提供任何额外的好处。最好只向您的存储库询问狗列表,除非您有服务层应该对该列表执行的操作?另外,请干净地格式化代码!有帮助!
  • 我确实有其他利用数据的方法,我只是将其作为一个简单的示例。你能推荐使用哪种 var 类型吗?
  • 根据程序的功能,最好以单例模式实现dogList

标签: java scope instance-variables local-variables


【解决方案1】:

在第一种情况下,您使用您的实例创建一个新的 ArrayList,并在离开该方法后保留对狗列表的引用。你在浪费内存。

此外,它是您的类中没有使用的字段,因此它会使您的代码杂乱无章,您可以删除这些无用的行。

它也可能是错误的来源。该变量已声明,并且具有暗示其用途的名称。稍后,其他开发人员可能会尝试将其用于其他用途,并且根据之前是否调用该方法,它会工作还是崩溃。

在第二种情况下,变量没有用,因为您可以立即返回 getter 的结果。但是编译器会为你处理好这些,所以你不必担心。

【讨论】:

  • 好的,那我应该使用本地变量吗?我对 2 中的差异感到困惑,谢谢
  • 在这种情况下,是的,除非你像可怕的袋熊建议的那样去记忆。即使您不再使用它,拥有实例字段也会将列表保留在内存中。
  • 好的,我希望将列表保存在内存中,但是在整个跑步者课程中以便调用它,例如 .get() 等?
  • 我不确定“浪费内存”是否真的是一个问题。过早的优化是魔鬼。
  • @NathanielFord 这不仅仅是在浪费内存。你正坐在一个你没有使用的参考资料中,你有一个你没有使用的领域,总的来说它很混乱。我添加了一段来表达这一点。
【解决方案2】:

这完全是个人观点,但您误解了服务层的典型用途,即:

public class DogService{
  Repository repository;
  public DogService(Repository repo){
    this.repository = repo;
  }

  public List<dogs> getAllDogs(){
    return this.repository.getAll();
  }
}

service 有责任知道在哪里寻找狗。它不会参与尝试记住特定的狗或查找它们:它delegates 对底层存储库负责。

回答您的问题,这意味着 方法和实例都不应该记住狗的列表。如果另一个方法,例如getAllDogNames 需要做一些时髦的事情,它可能需要一个实例变量:

public List<String> getAllDogNames(String prefix){
  List<Dog> dogs = this.getAllDogs();
  List<String> names = new ArrayList<String>();
  for (dog : dogs) {
    names.add(prefix + dog.getName()); //Or whatever
  }
}

但这应该推迟到适当的包装器。

【讨论】:

  • 这是一个有趣的解决方案。使用它时,我仍然可以在整个跑步者课程中将列表保存在内存中吗? IE。将来拨打电话,例如:listOfAllDogs.get(1) 等?
  • 请注意,除非您将列表保存为实例的成员字段,否则它不会“留在内存中”......除非底层存储库这样做。如果 repo 类似于 Hibernate,它会为您处理,您无需参与或担心它。这通常被认为是此类 ORM 库的责任:处理将 db 对象的权威表示保留在内存中的痛苦。
  • 我想我知道你的意思,但是这是我的第一个休眠项目,所以请耐心等待!为了能够从列表中删除一些狗实体,从而在课程后期从数据库中删除它们,我给出的跑步者类的示例是否不合适?
  • this.repository.delete(id) 是你想要的。 See here.
  • 好的,谢谢,这是否与删除然后重新保存列表具有相同的功能?
【解决方案3】:

如果dogList 不会更改,那么将其作为字段将允许您潜在地缓存它。对于dogs 可能不是一个好主意,它可能有小狗或死去,但如果它是一个静态列表或其他东西,它会有一些用途。

例如

 if (dogList == null) {
    dogList= new ArrayList<Dog>(); 
    dogList=dogRepository.getAll();
}

return dogList;

【讨论】:

  • 对不起,我不确定你的意思?谢谢
  • 即使dogList可以被缓存,也应该由Repository层而不是Service来处理。
  • 这听起来是个坏主意,因为数据库中可能有一些变化(可能不是通过程序),下次调用 findAll 时不会更新到客户端
  • @Thilo 我同意我们只是在谈论一些 DAO,但我认为这个问题很笼统
最近更新 更多