Как обмениваться данными между отдельными классами в Java

Каков наилучший способ обмена данными между отдельными классами в Java? У меня есть куча переменных, которые по-разному используются разными классами в отдельных файлах. Позвольте мне попытаться проиллюстрировать упрощенную версию моей проблемы:

Это был мой код раньше:

public class Top_Level_Class(){
    int x, y;

    // gets user input which changes x, y;
    public void main(){
       int p, q, r, s;
       // compute p, q, r, s
       doA(p,q,r);
       doB(q,r,s);
    }

    public void doA(int p, int q, int r){
       // do something that requires x,y and p, q, r
    }

    public void doB(int q, int r, int s){
       // does something else that requires x, y and q, r, s
    }
}

Теперь это выглядит примерно так:

public class Top_Level_Class(){
    int x, y;
    SomeClass1a a = new SomeClass1a();
    SomeClass1a b = new SomeClass1b();
    // gets user input which changes x, y;
    public void main(){
       int p, q, r, s;
       // compute p, q, r, s
       a.doA(p,q,r);
       b.doB(q,r,s);
    }

public class SomeClass1a() {  // in its own separate file
    public void doA(int p, int q, int r){
       // do something that requires x,y and p, q, r
    }
}


public class SomeClass1b() {  // in its own separate file
    public void doB(int q, int r, int s){
       // does something else that requires x, y and q, r, s
    }
}

В любом случае, должен ли я каждый раз передавать x и y (где x, y - переменные, хранящиеся в func вспомогательного класса)?

 a.set(x,y);
 a.doA(p,q,r);

Моя идея заключалась в том, чтобы иметь специальный контейнерный класс, в котором хранятся x и y. Класс верхнего уровня будет иметь экземпляр класса-контейнера и изменять x, y с помощью методов set.

// in the top level class:
Container c = new Container(x,y);
a.setContainer(c);
b.setContainer(c);

Мои вспомогательные классы также будут иметь экземпляр контейнера, и он будет указывать на тот же экземпляр, что и на верхнем уровне. Таким образом, они получают доступ к тем же x, y, что и на верхнем уровне.

Я хотел бы знать, должен ли я

  • Используйте класс контейнера
  • Загружать x,y каждый раз в подклассы
  • ?? Какой-то лучший метод ??

person f20k    schedule 12.12.2010    source источник
comment
Ответ здесь, к сожалению, «это зависит». Programmers.se может быть более подходящей целью для этого вопроса.   -  person bmargulies    schedule 12.12.2010
comment
Если внутренний класс не является статическим, то он также может получить доступ к членам родительского класса...   -  person Vojta    schedule 12.12.2010
comment
Это не внутренний класс, если он находится в другом файле. И это не подкласс, если он не расширяет суперкласс.   -  person Armand    schedule 12.12.2010
comment
Да, «подкласс» был неудачным выбором слов с моей стороны. Я отредактирую это.   -  person f20k    schedule 12.12.2010


Ответы (4)


Я предполагаю, что ответом на ваш вопрос является шаблон проектирования под названием Singleton. Это в основном позволяет вам получить и использовать один и тот же (и уникальный) экземпляр класса, когда вы хотите в вашей системе.

Вот его реализация (прошу прощения за возможные синтаксические ошибки, я не компилировал):

class Container{

  //eventually provides setters and getters
  public float x;
  public float y;
  //------------

  private static Container instance = null;
  private void Container(){

  }
  public static Container getInstance(){
    if(instance==null){
       instance = new Container();
      }
      return instance;
  }
}

затем, если в другом месте вашего кода вы импортируете контейнер, вы можете написать, например

Container.getInstance().x = 3;
temp = Container.getInstance().x;

и вы повлияете на атрибуты уникального экземпляра контейнера, который у вас есть в вашей системе.

Однако во многих случаях лучше использовать шаблон внедрения зависимостей, поскольку он уменьшает связь между различными компонентами.

person Andrea Sindico    schedule 14.12.2010
comment
Очень интересно. У него есть собственная статическая переменная. Просто интересно, как эта штука выходит за рамки? Если он статичен, не будет ли он существовать? Или мне установить его на ноль, когда я закончу с ним? - person f20k; 15.12.2010
comment
Извините, но я думаю, что не понял вашего вопроса :( в любом случае, поскольку его экземпляр является статическим, после инициализации он останется в существовании. Вам не нужно и вы не можете устанавливать для него значение null. Считайте его общим хранилищем ваши переменные :) Однако вот объяснение шаблона en.wikipedia.org/wiki/Singleton_pattern - person Andrea Sindico; 15.12.2010
comment
Хм, ну, синглтон будет иметь смысл, если мне нужно создать его только один раз. Однако моя функция верхнего уровня на самом деле является потоком, который будет создаваться/уничтожаться несколько раз в ходе выполнения программы. Ну, я полагаю, я могу просто перезаписывать значения каждый раз. - person f20k; 16.12.2010
comment
создание и уничтожение одного и того же потока много раз во время выполнения системы довольно странно. Возможно, вы захотите заснуть и разбудить его, когда это необходимо. - person Andrea Sindico; 16.12.2010
comment
Я пишу игру для андроида. Учитывая структуру, пользователь вполне может играть в игру так, что поток создается и уничтожается несколько раз. ОС Android уничтожит поток по мере необходимости, чтобы освободить ресурсы для других приложений. Хм. Возможно, усыпление может сработать, но я думаю, что андроид все равно уничтожит его, когда пользователь выйдет из игры. - person f20k; 20.12.2010
comment
Я хотел бы добавить, что вы найдете много людей, говорящих, что этот шаблон является чистым злом, потому что на самом деле это просто оболочка глобальной переменной. Проблема также в том, что в одноэлементной архитектуре зависимости классов могут быть неясными. Я лично считаю, что шаблон Singleton — это просто шаблон проектирования, помогающий вам быть уверенным, что этот класс будет иметь только один экземпляр. Сам по себе он не плохой, зависит от того, как его использовать. - person Andrea Sindico; 29.09.2012
comment
Используйте instance != null вместо !instance, поскольку ! не определено для этого типа аргумента. - person Saeed; 12.05.2014

Мне трудно понять, в чем ваша проблема - почему вы не хотите передавать x и y в качестве параметра?

Ну что ж. Предполагая, что вы этого не сделаете, я не вижу необходимости в новом классе контейнеров. Сделайте это следующим образом:

public class SubClass1a() {  // in its own separate file
    public void doA(Top_Level_Class caller, int p, int q, int r){
       // do something that requires x,y and p, q, r
       // **to get x use the expression term caller.getX() and caller.getY()**
    }
}

Конечно, вам нужно добавить общедоступные методы getX() и getY() в Top_Level_Class.

Если вы не хотите, чтобы SubClass1a зависел от Top_Level_Class, вы можете создать интерфейс, обеспечивающий доступ к переменным.

person AlanObject    schedule 12.12.2010
comment
Хм, хорошо. Придется больше смотреть на интерфейсы. Основная причина, по которой я не хотел передавать x, y каждый раз, заключается в том, что у меня есть несколько функций в нескольких подклассах, каждый из которых использует (x, y, z и т. д.), и мне казалось неправильным передавать по 6-8 переменных каждый время, когда я вызываю функцию. Раньше подклассы были зависимыми, но я пытаюсь удалить их из файла, чтобы их можно было использовать в другом проекте. - person f20k; 12.12.2010
comment
@ f20k Ваше внутреннее ощущение, что вы не хотите передавать 6-8 параметров методу, находится на правильном пути. Такие длинные списки параметров обычно намекают на то, что вам следует подумать об объединении этих параметров в объект или 2. - person dhable; 12.12.2010
comment
@Дэн, спасибо за твое предложение. Думаю реализовать контейнер. Это имеет большой смысл. Я просто беспокоился, что это будет плохой практикой программирования, если я буду делиться данными таким образом. - person f20k; 12.12.2010

Цитата Основная причина, по которой я не хотел каждый раз передавать x, y, заключается в том, что у меня есть несколько функций в нескольких подклассах, каждый из которых использует (x, y, z и т. д.), и было бы неправильно передавать 6-8 переменных. каждый раз, когда я вызываю функцию. Раньше подклассы были зависимыми, но я пытаюсь удалить их из файла, чтобы их можно было использовать в другом проекте. Цитата

Если это так, то вам лучше абстрагировать свои переменные в контейнерный класс. Если каждый экземпляр этих больше не зависимых классов будет использовать большое подмножество этих переменных, то имеет смысл иметь их все в одном экземпляре. Логически связанные переменные должны находиться в одном месте. Ваш подход должен быть примерно таким:

public class Top_Level_Class(){
Container container = new Container(x, y, p, q, r, s);
SubClass1a a = new SubClass1a(container);
SubClass1a b = new SubClass1b(container);
// gets user input which changes x, y using container's getters and setters
public void main(){
   // compute and set p, q, r, s
   a.doA();
   b.doB();
}

public class SubClass1a(Container c) {  // in its own separate file
    public void doA(c.getX, c.getY, c.getP, c.getQ, c.getR){
       // do something that requires x, y, p, q, and r
    }
}

public class SubClass1b(Container c) {  // in its own separate file

    public void doB(c.getX, c.getY, c.getQ, c.getR, c.getS){
       // does something else that requires x, y, q, r, and s
    }
}

public class Container(x, y, p, q, r, s) {
    //getters and setters for all variables
}

Это убережет вас от ситуации с передачей переменных спагетти-кода, и когда вы захотите позже использовать только один или два из этих классов, ваш код будет достаточно модульным, чтобы портировать только эти классы и ваш контейнер.

person Raskolnikov    schedule 12.12.2010
comment
Этот синтаксис неверен и кажется более сложным, чем первоначальное предложение. - person Armand; 12.12.2010

Этот вопрос немного сумасшедший - код в вопросе не компилируется.

public class Main {
    public static void main(String... args) {
        MutableDataContainer m = new MutableDataContainer();
        ImmutableDataContainer i = computeImmutableData();
        new ADoer().doA(m, i);
        new BDoer().doB(m, i);
    }
    ...
}

class MutableDataContainer {
    private int x, y;
    ... // getters and setters below
}

class ImmutableDataContainer {
    private final int p, q, r, s;
    ... // getters below
}

Вам также необходимо определить ADoer и BDoer.

person Armand    schedule 12.12.2010
comment
Извините, код, который я написал, поможет понять, что я хочу сделать. На самом деле это не работает. Фактический код на самом деле довольно сложен и содержит более 100 строк. В основном я пытаюсь разделить некоторые очень часто используемые переменные в классе top_level_class между вспомогательными классами в отдельных файлах. Вопрос в том, какой метод будет лучше - эффективный и oop-мудрый - person f20k; 12.12.2010