1

首先,这个问题会有点长,但为了完整地解释我的问题,我觉得我必须给你很多关于我的项目的信息,所以请多多包涵!

我在一家经常使用图表的公司工作,为了避免总是不得不从 scats 创建图表的麻烦,我决定创建一个新的 java 项目并创建一个“包”,我和我的同事可以使用它来创建这些图表。你可以称它们为通用的。

所以这个项目使用了构建器模式和大量的接口和抽象类。这个想法是客户端(开发人员)使用这些接口、模式和类并覆盖这些方法以适应流程。客户(开发人员)唯一剩下的事情就是填写这些方法并为他自己创建 UI 并发布程序。

该程序正在很好地形成,我创建了很多我非常自豪的功能(因为我是学生)我认为我已经很好地规划了整个过程,但我遇到了一些问题!

首先,让我向您展示这些类并解释数据流(我会尽可能短):

首先是 GUI(这是一个用户必须自己创建的类,但他可以使用内置包通过以下代码创建他的图表):

ChartBuilder cb = new LineChartBuilder();
                  Director d = new Director();
d.buildTypeOne(cb, "Hello", PeriodSelection.HOUR,"");

有了这个,导演现在准备建立一个图表。

PeroidSelection.Hour是一个设置标准时间的枚举,在这种情况下它将图表类别轴设置为我们打开我们的时间,因此收集的数据知道它必须每小时获取数据(在这种情况下从 8.00 - 19.00)原因为什么这是一个枚举是因为这些类型的时期是最后唯一可以改变的是我们的开放日期和时间,然后我们将能够很容易地改变!这是预览PeriodSelection enum

    public enum PeriodSelection{
    HOUR(new String[]{"8:00", "9:00", "10:00", "11:00", "12:00", "13:00", "14:00", "15:00", "16:00", "17:00", "18:00", "19:00"}),
    MONTH(new String[]{"Jan", "Feb", "Marts", "April", "Maj", "Juni", "Juli", "Agu", "Sep", "Oct", "Nov", "Dec"}),
    DAYS(new String[]{"Mandag", "Tirsdag", "Onsdag","Torsdag","Fredag","Lørdag","Søndag"});

    private String[] timeIntervals;
    private PeriodSelection(String[] timeIntervals){
        this.timeIntervals = timeIntervals;
    }
    public String[] getTimeIntervals(){
        return timeIntervals;
    }
}

进入 Director,director 现在已准备好构建图表,但首先它必须从数据库中收集数据:

    public void buildTypeOne(ChartBuilder builder, String title, PeriodSelection selection, String queueName){
    try {
        builder.setObjectList(stat.getData(queueName, start, end));
    } catch (DopeDBException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }

    builder.selection = selection;
    builder.initiate(title);
    builder.createSeries();
    builder.createSymbol();

    builder.createTable();
}

正如您所看到的,构建器是以某种方式构建的,这是因为图表由表格和图表组成,并且这两者必须链接在一起,我不会详细介绍图表,因为它与我的问题。

现在,方法的第一行中显示的 stat 类buildTypeOneextends 和调用的抽象类statisticPattern看起来像这样:

public abstract class StatisticPattern {


protected ArrayList<ObjectInterface> cq = new ArrayList<>();
protected ObjectInterface contact;
protected ProviderInterface p;
/**
 * 
 * 
 * {@link Constructor}
 */
public StatisticPattern(){
    try {
        p = new Provider();
    } catch (DopeDBException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
/**
 * 
 * @param name
 * @param start
 * @param end
 * @return
 * @throws SQLException
 * @throws DopeDBException
 */
protected ArrayList<ObjectInterface> getData(String name, DateTime start, DateTime end) throws SQLException, DopeDBException{
    return cq;
}
/**
 * 
 * @param contact2
 */
protected void processSingleQueueData(ObjectInterface contact2) {
}
/**
 * 
 * @param queueName
 * @throws SQLException
 */
protected void obtainNewData(String queueName) throws SQLException {

}

/**
 * 
 * @param name
 * @param start
 * @param end
 * @return
 */
protected boolean doIhaveIt(String name, DateTime start, DateTime end) {
    return false;
}
/**
 * 
 * @param start
 * @param end
 * @return
 */
protected boolean checkDatas(DateTime start, DateTime end) {
    return start.toDateMidnight().isEqual(end.toDateMidnight());
}
/**
 * 
 * @param start
 * @param end
 * @return
 */
protected Integer daysBetween(DateTime start, DateTime end) {
    return  end.dayOfYear().get()-start.dayOfYear().get();

}

如前所述,此类的目的是我们的开发人员将扩展类并覆盖方法,以便主管可以找到这些方法并使用它们,他们选择实现和填充方法的方式因程序而异。

在这个程序中,统计类看起来像这样:

public class Statistics extends StatisticPattern {
private DateTime start;
private DateTime end;


/**
 *  This class checks whether the program has already collected the data
 * @Override
 */
public ArrayList<ObjectInterface> getData(String name, DateTime start, DateTime end) throws DopeDBException{
    if (this.start.equals(start) && this.end.equals(end)) {
        if (name.equalsIgnoreCase("All")) {
            return cq;
        }else if (doIhaveIt(name, start, end)) {
            return cq;
        }
    }else {
        try {
            obtainNewData(name);
        } catch (SQLException e) {
            e.printStackTrace();
        }
    }
    return cq;
}
@Override
protected void obtainNewData(String queueName) throws SQLException {
    setDates(start, end);
    this.cq = p.obtainData(start, end, queueName);

}

如您所见,我创建了自己的方法实现,getData该方法调用该obtainNewData方法,然后从 p (我们的提供程序类 - 也称为与数据库的连接)获取数据。

您可能已经猜到的提供程序类也实现和接口,其中方法中只有一个obtainData方法

public interface ProviderInterface {

public ArrayList<ObjectInterface> obtainData(DateTime start, DateTime end, String name) throws SQLException;

}

同样,开发人员必须实现此方法,但可以随心所欲地填充它。这里最重要的是返回类型是 ObjectInterface 类型的 ArrayList:

public interface ObjectInterface {

HashMap<String, Integer> data = new HashMap<String, Integer>();
String type = "";

public String getType();
public void addData(String key, Integer value);
public Integer getData(Object key);

}

基本上,它必须实现一个包含图表应填充的所有数据的哈希图。此数据将在创建对象时添加,然后添加到提供程序中的列表中,然后将返回此列表,然后 Director 将其设置为 chartbuilders 的数据列表,然后填充图表。

在这种情况下,必须填充图表的最终对象如下所示:

public class ContactQueue implements ObjectInterface {

    private HashMap<String, Integer> data = new HashMap<String, Integer>();
    private String type;
    public ContactQueue(String type){
        this.type = type;
    }
    public String getType(){
        return type;
    }
    public void addData(String key, Integer value){
        if (data.containsKey(key)) {
            Integer i = data.get(key);
            data.put(key, value+i);
        }else {
            data.put(key, value);
        }

    }
    public Integer getData(Object key){
        return data.get(key);
    }
    public String toString(){
        return type;
    }
}

现在问题来了!

当只收集一种类型的数据时,所有这些都可以完美运行。但是我目前正在处理的程序必须从 5 个不同的表中获取数据,所有这些表都必须添加到他们的每个图表中我的问题是我将如何设计它以便它选择数据库表?并返回该特定表的列表?

我已经尝试过以下代码:

        if (name.equalsIgnoreCase("Besvarelse")) {
        return besvarelse25(start, end);
    }else if (name.equalsIgnoreCase("intern")) {
        return intern(start, end);
    }else if (name.equalsIgnoreCase("besvarelseProcent")) {
        return besvarelseProcent(start,end);
    }else if (name.equalsIgnoreCase("Email_data")) {
        return email_data(start, end);
    }else if (name.equalsIgnoreCase("Email_Hånd")) {
        return email_haand(start, end);
    }else if (name.equalsIgnoreCase("Email_Antal")) {
        return email_antal(start, end);
    }
    else if (name.equalsIgnoreCase("Henvendelser")) {
        return henvendelser(start, end);
    }

然而,至少可以说,这似乎有点多余,而且很难看。

我曾考虑过再次创建一个枚举,客户(开发人员)每次想要创建一个新程序时都必须更改,但我不确定这是正确的方法吗?

我也很想听听您对整个项目的看法?我是成功了还是失败了?

感谢您阅读,我将期待阅读您的回复

4

2 回答 2

1

老实说,我没有完全阅读 OP 并直接提出问题。道歉......
任何时候你有这样的代码:

if (name.equalsIgnoreCase("Besvarelse")) {
        return besvarelse25(start, end);
    }else if (name.equalsIgnoreCase("intern")) {
        return intern(start, end);
    }else if (name.equalsIgnoreCase("besvarelseProcent")) {
        return besvarelseProcent(start,end);
    }else if (name.equalsIgnoreCase("Email_data")) {
        return email_data(start, end);
    }else if (name.equalsIgnoreCase("Email_Hånd")) {
        return email_haand(start, end);
    }else if (name.equalsIgnoreCase("Email_Antal")) {
        return email_antal(start, end);
    }  

考虑使用工厂模式。工厂模式是这种情况下的标准方式(另请阅读抽象工厂)

于 2012-12-17T15:11:53.093 回答
1

意见:因为您似乎在最后根据后备数据库进行过滤,所以解决方案很简单/优雅。是的,它是多余且丑陋的,但具有 5 个相似信息表的模式也是如此(如果我没看错的话)。如果它有效,我认为你没有问题。

如果您担心需要选择“正确类型”的表格,您可能会找到每个表格的通用质量:

像->

  SELECT 
    generic.specificField AS "genericKey",
    ....
  FROM
    TableOne generic

然后,您可以创建一个 HashMap(或对象,您的调用),以满足您设计的某种程度的一致性。

再次类似 ->

  for(Field f : resultSet.values())//Pseudo Code, obviously javax.sql is a bit more complex
    hashMap.put(f.getName(), f.getValue());
...
  return genericProcessing(hashMap, start, end);

因为您知道键/方法(由您的 SQL 别名定义),所以您有一个简单的解决方法。但是,如果这是一个公共 API,那么更“严格”(接口)的东西可能是更好的选择。

如果您的数据不相关,那么我会说您的设计反映了数据。这没什么不好。

第二种观点,上面建议的工厂模式只是另一种抽象形式。Java 生态系统中的很多人都喜欢它,但也有很多人讨厌它——我在这里属于第二阵营)。一般来说,我会先尝试抽象你的问题,如果你不能抽象它可能很简单。在您的情况下,我认为您可能可以使用方法/查询对其进行抽象。如果你不能,那么跳到一个类型(工厂是一种方法)可能是你最好的答案。

于 2012-12-17T15:23:52.153 回答