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

时间:2014-11-01 23:31:11

标签: java c++ algorithm design-patterns composition

我以一种“平坦化”的方式从合成层次结构中导出数据。输出数据。例如,我有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

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

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

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

1 个答案:

答案 0 :(得分:3)

听起来像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

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