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

3
我正在以“展平”数据的方式从组合层次结构中导出数据。例如,我有4个类,每个类都有一个下一级层次结构的集合:
SchoolData -> StudentData -> ExamRecord
我希望以一种扁平化的方式导出它,使某些方面得到体现。
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 ++,但语言不应该那么重要。

1个回答

4
听起来像是访问者模式。从维基百科链接中可以得知,“访问者设计模式是一种将算法与其操作的对象结构分离的方法。”

Wikipedia文章中的Java示例

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

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

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

我不确定这个。我认为访问者模式是用于处理具有不同子类对象的层次结构,但所有对象都是相同根类的子类,即它们都有一些共同点。我不认为问题的情况符合此模式。如果您认为它符合,请提供一个实际案例中如何使用它的示例--而不仅仅是来自维基百科页面的图表,其与实际问题的关系并不明显。 - ajb
@ajb 添加了一个示例实现。 - Elliott Frisch

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接