17

这对我来说是一件令人讨厌的事情……我是一名在 Java 中从事 JSP 项目的 PHP 人员。我知道如何通过太多代码和完全缺乏技巧来做我正在尝试的事情。

我宁愿做对。情况如下:

我正在写一个小型显示器,以向客户展示他们可以根据浇水组 (ABCDE) 浇灌草坪的日期以及一年中的什么时间。我们的季节是这样的: 夏季(5-1 到 8-31) 春季(3-1 到 4-30) 秋季(9-1 到 10-31) 冬季(11-1 到 2-28)

一个例子可能是:

如果我在 A 组,以下是我允许的时间: 冬季:仅限周一 春季:周二、周四、周六 夏季:任何一天 秋季:周二、周四、周六

如果我用 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';

我可以制作天数数组 (array("Tuesday","Thursday","Saturday")) 等,但这对于我真正想要完成的事情来说并不是必需的。

我还需要设置数组来确定我所处的季节:

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

谁能提出一个非常酷的方法来做到这一点?我会有今天的约会和群信。我需要一天(M)或一系列天(tTS),(Any)离开我的职能。

4

12 回答 12

11

您可以使用 Hashtables(或其他一些 Map)执行基本相同的代码:

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 不是一种动态语言,它在语言级别上没有散列。

注意:您也许可以做一个更好的解决方案,当我阅读您的问题时,这只是突然出现在我的脑海中。

于 2008-08-15T23:16:52.383 回答
9

不要试图像 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实现,例如HashMapTreeMap

于 2008-08-16T00:21:05.763 回答
6

似乎每个人都试图找到 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);
...

当然,这也可能是不对的。我会让每个季节成为一个对象,也许每个工作日列表也是一个对象。无论如何,它比试图模仿您的 PHP 代码的笨拙的 Hashtable 更容易重用、理解和扩展。当然,PHP 也有对象,你应该尽可能以类似的方式使用它们,而不是你的超级数组。不过,我确实理解作弊的诱惑。PHP 让它变得如此简单,如此有趣!

于 2008-08-16T00:28:34.220 回答
4

这是它可能看起来的一种方式,你可以弄清楚其余的:

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 );
于 2008-08-16T07:37:11.967 回答
3

我不是 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";
于 2008-08-15T23:56:20.010 回答
2

我完全不知道为什么你们中的一些人似乎认为向代码扔大量对象是要走的路。例如,恰好有四个季节,它们不做也不存储任何东西。它如何简化使它们成为对象的任何事情?Wing 非常正确,这些应该是常量(或者可能是枚举)。

Bruce 需要的只是一个查找表。他不需要对象和接口的层次结构;他需要一种方法来根据季节和组标识符查找时间表。将事物转化为对象只有在它们具有责任或状态时才有意义。如果两者都没有,那么它们只是标识符,为它们构建特殊对象只会使代码库更大。

例如,您可以Group构建每个包含一组时间表字符串(每个季节一个)的对象,但如果所有Group对象都提供查找功能,那么您已经以一种不太直观的方式重新发明了查找表。如果他必须查找组,然后查找时间表,他所拥有的只是一个两步查找表,编码时间更长,更容易出错,并且更难维护。

于 2008-08-16T01:07:35.577 回答
2

我和那些建议在对象中封装函数的人在一起。

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)

于 2008-08-16T12:04:54.377 回答
1

我同意你绝对应该把这个逻辑放在干净的界面后面:

public String lookupDays(String group, String date);

但也许您应该将数据粘贴在属性文件中。我不反对在源文件中硬编码这些数据,但正如您所注意到的,Java 在嵌套集合方面可能会非常冗长。您的文件可能如下所示:

A.夏天=M A.春天=
tTS B.夏天
=T

通常我不喜欢将这样的静态数据移动到外部文件,因为它增加了数据和使用它的代码之间的“距离”。但是,每当您处理嵌套集合,尤其是地图时,事情会变得非常丑陋,非常快。

如果你不喜欢这个想法,也许你可以这样做:

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);
  }

}

您失去了一些可读性,但至少数据更接近将要使用的位置。

于 2008-08-16T00:53:11.563 回答
1

更好的解决方案可能是将所有数据放入数据库中,而不是在源中硬编码或使用属性文件。

使用数据库会更容易维护,并且有多种 免费 数据库引擎可供选择。

其中两个数据库引擎完全用 Java 实现,只需包含一个 jar 文件就可以嵌入到应用程序中。当然,它有点重量级,但它更具可扩展性且更易于维护。仅仅因为今天有 20 条记录并不意味着以后不会因为需求变化或功能蔓延而出现更多记录。

如果在几周或几个月后,您决定要添加例如一天中的浇水时间限制,那么如果您已经在使用数据库,那么添加该功能会容易得多。即使这从未发生过,您也已经花费了几个小时来学习如何在应用程序中嵌入数据库。

于 2008-08-16T01:46:37.243 回答
1

“日期”是否必须是参数?如果您只是显示当前的浇水时间表,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 是键,然后 groupToScheduledDays 的 Maps 是值。

于 2008-08-16T04:35:49.557 回答
0

没有漂亮的解决方案。Java 就是不能很好地完成这样的事情。如果您希望字符串作为索引(键),迈克的解决方案几乎就是这样做的方法。如果散列设置太难看,另一种选择是将字符串附加在一起(无耻地从 Mike 那里窃取并修改):

Hashtable<String, String> schedule = new Hashtable<String, String>();
schedule.put("A-Winter", "M");
schedule.put("A-Spring", "tTS");

然后查找:

String val = schedule.get(group + "-" + season);

如果您对一般的丑陋不满意(我不怪您),请将其全部放在方法调用后面:

String whenCanIWater(String group, Date date) { /* ugliness here */ }
于 2008-08-15T23:27:13.673 回答
0
于 2018-01-30T01:55:14.090 回答