2014-11-01 1 views
2

Я экспортирую данные из иерархии композиций таким образом, что «сглаживает данные». Так, например, у меня есть 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.

Очевидно, что я мог бы реализовать соответствующие геттеры и вытащить все данные на вызов функции верхнего уровня, который печатает все, но мне интересно, есть ли более элегантный способ сделать это.

Я использую C++, но язык не должен иметь большого значения.

ответ

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 

Конечно, есть и другие способы решения этой конкретной проблемы.

+0

Не уверен в этом. Я думаю, что шаблон Visitor предназначен для работы с иерархией, которая имеет разные подклассы объектов, но где все объекты являются подклассами одного и того же корневого класса, т. Е. Все они имеют что-то общее. Я не думаю, что случай в вопросе соответствует этой схеме. Если вы думаете, что это так, отправьте пример того, как он будет использоваться в фактическом случае, а не только диаграмма со страницы Википедии, отношение которой к реальной проблеме не очевидно. – ajb

+0

@ajb Добавлен пример реализации. –