Массивы массивов в Java - PullRequest
       49

Массивы массивов в Java

14 голосов
/ 16 августа 2008

Это неприятно для меня ... Я - парень из PHP, работающий на Java над проектом JSP. Я знаю, как делать то, что я пытаюсь, используя слишком много кода и полное отсутствие изящества.

Я бы предпочел сделать это правильно. Вот ситуация:

Я пишу небольшой дисплей, чтобы показать клиентам, в какие дни они могут поливать газоны в зависимости от своей группы полива (ABCDE) и в какое время года. Наши сезоны выглядят так: Лето (с 5-1 до 8-31) Весна (с 3-1 до 4-30) Осень (с 9-1 до 10-31) Зима (с 11-1 до 2-28)

Примером может быть:

Если я в группе А, вот мои разрешенные времена: Зима: только по понедельникам Весна: вторник, четверг, суббота Лето: любой день Осень: вт, четверг, сб

Если бы я писал это на PHP, я бы использовал такие массивы:

//M=Monday,t=Tuesday,T=Thursday.... etc
$schedule["A"]["Winter"]='M';
$schedule["A"]["Spring"]='tTS';
$schedule["A"]["Summer"]='Any';
$schedule["A"]["Fall"]='tTS';
$schedule["B"]["Winter"]='t';

Я МОГУ сделать массивы дней (массив («вторник», «четверг», «суббота»)) и т. Д., Но это не обязательно для того, что я действительно пытаюсь выполнить.

Мне также нужно настроить массивы, чтобы определить, в какое время года я нахожусь:

$seasons["Summer"]["start"]=0501;
$seasons["Summer"]["end"]=0801;

Кто-нибудь может предложить действительно крутой способ сделать это? У меня будет сегодняшняя дата и групповое письмо. Мне нужно будет выходить из функции один день (M) или ряд дней (TTS), (Любой).

Ответы [ 12 ]

9 голосов
/ 16 августа 2008

Не пытайтесь быть такими же динамичными, как PHP. Вы можете попытаться сначала определить , что вам нужно.

interface Season
{
    public string getDays();
}

interface User
{
    public Season getWinter();
    public Season getSpring();
    public Season getSummer();
    public Season getFall();
}

interface UserMap
{
    public User getUser(string name);
}

И, пожалуйста, прочитайте документацию Hashtable перед ее использованием. Этот класс синхронизирован, что означает, что каждый вызов защищен от многопоточности, что действительно замедляет доступ, когда вам не нужна дополнительная защита. Пожалуйста, используйте любую Map реализацию вместо HashMap или TreeMap .

9 голосов
/ 16 августа 2008

Вы можете сделать, по сути, тот же код с Hashtables (или другой картой):

Hashtable<String, Hashtable<String, String>> schedule
    = new Hashtable<String, Hashtable<String, String>>();
schedule.put("A", new Hashtable<String, String>());
schedule.put("B", new Hashtable<String, String>());
schedule.put("C", new Hashtable<String, String>());
schedule.put("D", new Hashtable<String, String>());
schedule.put("E", new Hashtable<String, String>());

schedule.get("A").put("Winter", "M");
schedule.get("A").put("Spring", "tTS");
// Etc...

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

Примечание. Возможно, вам удастся найти лучшее решение, и это просто пришло мне в голову, когда я читаю ваш вопрос.

6 голосов
/ 16 августа 2008

Кажется, что каждый пытается найти способ Java сделать это так, как вы делаете это в PHP, а не так, как это должно быть сделано в Java. Просто рассмотрите каждую часть вашего массива как объект или, по крайней мере, первый уровень массива как объект, а каждый подуровень - как переменные внутри объекта. Создайте структуру данных, которую вы заполняете указанными объектами и получаете доступ к объектам через данные средства доступа к структуре данных.

Что-то вроде:

class Schedule
{
  private String group;
  private String season;
  private String rundays;
  public Schedule() { this.group = null; this.season = null; this.rundays= null; }
  public void setGroup(String g) { this.group = g; }
  public String getGroup() { return this.group; }
  ...
}

public ArrayList<Schedule> schedules = new ArrayList<Schedule>();
Schedule s = new Schedule();
s.setGroup(...);
...
schedules.add(s);
...

Конечно, это, вероятно, тоже неправильно. Я бы сделал каждый сезон объектом, а может быть, каждый список дней недели тоже объектом. В любом случае, его легче использовать, понимать и расширять, чем скомбинированный Hashtable, который пытается имитировать ваш PHP-код. Конечно, в PHP тоже есть объекты, и вы должны использовать их аналогичным образом вместо своих uber-массивов, где это возможно. Я все же понимаю соблазн обмануть. PHP делает это так просто и так весело!

4 голосов
/ 16 августа 2008

Вот один из способов, которым это может выглядеть, остальное можно понять:

A = new Group();
A.getSeason(Seasons.WINTER).addDay(Days.MONDAY);
A.getSeason(Seasons.SPRING).addDay(Days.TUESDAY).addDay(Days.THURSDAY);
A.getSeason(Seasons.SPRING).addDays(Days.MONDAY, Days.TUESDAY, ...);

schedule = new Schedule();
schedule.addWateringGroup( A );
3 голосов
/ 16 августа 2008

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

Если используются именованные константы, где, например:

int A = 0;
int B = 1;
int C = 2;
int D = 3;

int Spring = 0; 
int Summer = 1;
int Winter = 2; 
int Fall = 3;
...

Тогда константы служат более читаемыми индексами массива:

schedule[A][Winter]="M";
schedule[A][Spring]="tTS";
schedule[A][Summer]="Any";
schedule[A][Fall]="tTS";
schedule[B][Winter]="t";

Использование перечислимых типов:

enum groups
{
  A = 0,
  B = 1,
  C = 2,
  D = 3
}

enum seasons
{
  Spring = 0,
  Summer = 1,
  Fall = 2,
  Winter = 3
}
...
schedule[groups.A][seasons.Winter]="M";
schedule[groups.A][seasons.Spring]="tTS";
schedule[groups.A][seasons.Summer]="Any";
schedule[groups.A][seasons.Fall]="tTS";
schedule[groups.B][seasons.Winter]="t";
2 голосов
/ 16 августа 2008

Я с теми, кто предлагает инкапсулирующую функцию в объектах.

import java.util.Date;
import java.util.Map;
import java.util.Set;

public class Group {

    private String groupName;

    private Map<Season, Set<Day>> schedule;

    public String getGroupName() {
        return groupName;
    }

    public void setGroupName(String groupName) {
        this.groupName = groupName;
    }

    public Map<Season, Set<Day>> getSchedule() {
        return schedule;
    }

    public void setSchedule(Map<Season, Set<Day>> schedule) {
        this.schedule = schedule;
    }

    public String getScheduleFor(Date date) {
        Season now = Season.getSeason(date);
        Set<Day> days = schedule.get(now);
        return Day.getDaysForDisplay(days);
    }

}

РЕДАКТИРОВАТЬ: Кроме того, ваши диапазоны дат не учитывают високосные годы:

Наши времена года выглядят так: Лето (От 5-1 до 8-31) пружина (от 3-1 до 4-30) Осень (с 9-1 до 10-31) Зима (с 11-1 до 2-28)

2 голосов
/ 16 августа 2008

Я в полном недоумении, почему некоторые из вас, кажется, думают, что выбрасывать куски объектов в код - это путь. Например, есть ровно четыре сезона, и они не делают или ничего не хранят . Как это упрощает что-либо, чтобы сделать их объектами? Wing совершенно прав, что это, вероятно, должны быть константы (или, может быть, перечисления).

В сущности, Брюсу нужна просто таблица поиска. Ему не нужна иерархия объектов и интерфейсов; ему нужен способ поиска расписания на основе сезона и идентификатора группы. Превращение вещей в объекты имеет смысл, только если у них есть обязанности или состояние. Если у них нет ни того, ни другого, то они просто идентификаторы, а создание специальных объектов для них просто увеличивает кодовую базу.

Вы можете построить, например, Group объекты, каждый из которых содержит набор строк расписания (по одной на каждый сезон), но если все, что делает объект Group, это обеспечивает функциональность поиска, то вы я изобрел таблицу поиска гораздо менее интуитивным способом. Если ему нужно просмотреть группу, а затем просмотреть расписание, у него будет только двухэтапная таблица поиска, для написания которой потребовалось больше времени, скорее всего, она будет содержать ошибки и будет труднее поддерживать.

1 голос
/ 16 августа 2008

Должна ли "дата" быть параметром? Если вы просто показываете текущее расписание полива, класс WateringSchedule сам может определить, какой сегодня день и, следовательно, какой это сезон. Тогда просто есть метод, который возвращает карту, где ключ является буквой группы. Что-то вроде:

public Map<String,List<String>> getGroupToScheduledDaysMap() {
  // instantiate a date or whatever to decide what Map to return
}

Тогда на странице JSP

<c:forEach var="day" items="${scheduler.groupToScheduledDaysMap["A"]}">
   ${day}
</c:forEach>

Если вам нужно показывать расписания для более чем одного сезона, у вас должен быть метод в классе WateringSchedule, который возвращает карту, где Seasons - это ключи, а затем Maps of groupToScheduledDays - значения.

1 голос
/ 16 августа 2008

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

Использование базы данных будет намного проще в обслуживании, и есть разнообразие из свободных баз данных движков на выбор.

Два из этих механизмов баз данных полностью реализованы на Java и могут быть встроены в приложение, просто включив файл JAR. Это немного тяжеловесно, конечно, но это гораздо более масштабируемо и проще в обслуживании. Тот факт, что сегодня существует 20 записей, не означает, что их не будет больше из-за изменения требований или появления новых функций.

Если через несколько недель или месяцев вы решите добавить, скажем, ограничения времени полива, вам будет намного проще добавить эту функцию, если вы уже используете базу данных. Даже если этого никогда не произойдет, вы потратили несколько часов, изучая, как встроить базу данных в приложение.

1 голос
/ 16 августа 2008

Я согласен с тем, что вы должны обязательно поместить эту логику в чистый интерфейс:

public String lookupDays(String group, String date);

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

A.Summer = M
A.Spring = TTS
B.Summer = Т

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

Если вам не нравится эта идея, возможно, вы можете сделать что-то вроде этого:

public class WaterScheduler
{
  private static final Map<String, String> GROUP2SEASON = new HashMap<String, String>();
  static
  {
    addEntry("A", "Summer", "M");
    addEntry("A", "Spring", "tTS");
    addEntry("B", "Summer", "T");
  }

  private static void addEntry(String group, String season, String value)
  {
    GROUP2SEASON.put(group + "." + season, value);
  }

}

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

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...