java - 需要来自整个组合层次结构的数据的操作模式

标签 java c++ algorithm design-patterns composition

我正在以一种“扁平化”数据的方式从合成层次结构中导出数据。因此,例如,我有 4 个类,每个类都包含层次结构中下一个类的集合:

学校数据 -> 学生数据 -> 考试记录

我想以一种扁平化的方式导出它,这样

baker elementary,dan,3/2/2001,A
baker elementary,dan,3/3/2001,B
baker elementary,dan,3/3/2001,A
baker elementary,dan,3/5/2001,C
baker elementary,kim,3/5/2001,A
baker elementary,kim,3/5/2001,B
thompson middle school,alex,1/5/2001,A

其中日期和成绩是 examrecord 的成员,学生姓名是 StudentData 的字符串成员,学校名称是 SchoolData 的字符串成员。

显然,我可以实现适当的 getter 并将所有数据提取到打印出所有内容的顶级函数调用,但我想知道是否有更优雅的方法来执行此操作。

我正在使用 C++,但语言应该不是那么重要。

最佳答案

听起来像 Visitor pattern ;从链接的维基百科条目中,访问者设计模式是一种将算法与其运行的对象结构分开的方法。

Java example from Wikipedia article

编辑 根据下面的评论,这是一个带有测试框架的完整示例。

static interface IGradeElementVisitor {
    String visit(ExamRecord er);

    String visit(StudentData sd);

    String visit(SchoolData sd);
}

static interface IGradeElement {
    void accept(IGradeElementVisitor igev);
}

static class GradeElementVisitor implements IGradeElementVisitor {

    @Override
    public String visit(ExamRecord er) {
        StringBuilder sb = new StringBuilder();
        DateFormat df = new SimpleDateFormat("M/d/yyyy");
        sb.append(df.format(er.date)).append(",");
        sb.append(er.grade);
        return sb.toString();
    }

    @Override
    public String visit(StudentData sd) {
        StringBuilder sb = new StringBuilder();
        sb.append(sd.name).append(",");
        return sb.toString();
    }

    @Override
    public String visit(SchoolData sd) {
        StringBuilder sb = new StringBuilder();
        for (StudentData student : sd.students) {
            for (ExamRecord er : student.records) {
                sb.append(sd.name);
                sb.append(",");
                sb.append(visit(student));
                sb.append(visit(er));
                sb.append(System.lineSeparator());
            }
        }
        return sb.toString();
    }

}

static class ExamRecord implements IGradeElement {
    public ExamRecord(Date date, String grade) {
        this.date = date;
        this.grade = grade;
    }

    Date date;
    String grade;

    public void accept(IGradeElementVisitor igev) {
        igev.visit(this);
    }
}

static class StudentData implements IGradeElement {
    public StudentData(String name, List<ExamRecord> records) {
        this.name = name;
        this.records = records;
    }

    String name;
    List<ExamRecord> records;

    public void accept(IGradeElementVisitor igev) {
        igev.visit(this);
    }
}

static class SchoolData implements IGradeElement {
    public SchoolData(String name, List<StudentData> students) {
        this.name = name;
        this.students = students;
    }

    String name;
    List<StudentData> students;

    public void accept(IGradeElementVisitor igev) {
        igev.visit(this);
    }
}

public static void main(String[] args) {
    List<ExamRecord> dans = new ArrayList<>();
    dans.add(new ExamRecord(new Date(2001, 2, 2), "A"));
    dans.add(new ExamRecord(new Date(2001, 2, 3), "B"));
    dans.add(new ExamRecord(new Date(2001, 2, 3), "A"));
    dans.add(new ExamRecord(new Date(2001, 2, 5), "C"));

    List<ExamRecord> kims = new ArrayList<>();
    kims.add(new ExamRecord(new Date(2001, 2, 5), "A"));
    kims.add(new ExamRecord(new Date(2001, 2, 5), "B"));
    List<ExamRecord> alexs = new ArrayList<>();
    alexs.add(new ExamRecord(new Date(2001, 0, 5), "A"));

    StudentData dan = new StudentData("dan", dans);
    StudentData kim = new StudentData("kim", kims);
    StudentData alex = new StudentData("alex", alexs);
    List<StudentData> bakers = new ArrayList<>();
    bakers.add(dan);
    bakers.add(kim);
    List<StudentData> thompsons = new ArrayList<>();
    thompsons.add(alex);
    List<SchoolData> schools = new ArrayList<>();
    schools.add(new SchoolData("baker elementary", bakers));
    schools.add(new SchoolData("thompson middle school", thompsons));
    IGradeElementVisitor visitor = new GradeElementVisitor();
    for (SchoolData school : schools) {
        System.out.print(visitor.visit(school));
    }
}

输出是(按要求),

baker elementary,dan,3/2/3901,A
baker elementary,dan,3/3/3901,B
baker elementary,dan,3/3/3901,A
baker elementary,dan,3/5/3901,C
baker elementary,kim,3/5/3901,A
baker elementary,kim,3/5/3901,B
thompson middle school,alex,1/5/3901,A

当然,还有其他方法可以解决这个特定问题。

关于java - 需要来自整个组合层次结构的数据的操作模式,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/26694376/

相关文章:

python - 为什么以这种方式使用集合在 Python 中生成素数不起作用?

c++ - 自定义预览面板 - 适用于 Windows 7,不适用于 Vista

c++ - 在颜色空间之间转换图像

c++ - 取消引用无效指针时如何在 Visual C++ 2017 调试器中出错?

java - 每次迭代保存模拟数据的最佳策略是什么?

php - 分析英文文本句子以检测 PHP 中的押韵

java - 使 Tomcat 忽略 WEB-INF/LIB 中的 Servlet

java - JSF 和/或 SEAM 中是否有内置的 Y/N 和 boolean 值转换器可与 h :selectBooleanCheckbox? 一起使用

java - 无法解析主机 "<URL here>"没有与主机名关联的地址

java - 捕获数据并将其传递到文本字段中