0

I'm new to OOP and a lot of times I become stumped in situations similar to this example:

Task: Generate an XML document that contains information about a person. Assume the information is readily available in a database. Here is an example of the structure:

<Person>
    <Name>John Doe</Name>
    <Age>21</Age>
    <Address>
        <Street>100 Main St.</Street>
        <City>Sylvania</City>
        <State>OH</State>
    </Address>
    <Relatives>
        <Parents>
            <Mother>
                <Name>Jane Doe</Name>
            </Mother>
            <Father>
                <Name>John Doe Sr.</Name>
            </Father>
        </Parents>
        <Siblings>
            <Brother>
                <Name>Jeff Doe</Name>
            </Brother>
            <Brother>
                <Name>Steven Doe</Name>
            </Brother>
        </Siblings>
    </Relatives>
</Person>
  • Ok lets create a class for each tag (ie: Person, Name, Age, Address) Lets assume each class is only responsible for itself and the elements directly contained
  • Each class will know (have defined by default) the classes that are directly contained within them
  • Each class will have a process() function that will add itself and its children to the XML document we are creating
  • When a child is drawn, as in the previous line, we will have them call process() as well
  • Now we are in a recursive loop where each object draws their children until all are drawn

  • But what if only some of the tags need to be drawn, and the rest are optional? Some are optional based on if the data exists (if we have it, we must draw it), and some are optional based on the preferences of the user generating the document

  • How do we make sure each object has the data it needs to draw itself and its children? We can pass down a massive array through every object, but that seems shitty doesn't it? We could have each object query the database for it, but that's a lot of queries, and how does it know what its query is?
  • What if we want to get rid of a tag later? There is no way to reference them.

I've been thinking about this for 20 hours now. I feel like I am misunderstanding a design principle or am just approaching this all wrong. How would you go about programming something like this?

I suppose this problem could apply to any scenario where there are classes that create other classes, but the classes created need information to run. How do I get the information to them in a way that doesn't seem messy?

  • Are you talking about a way to dynamically port data from a database to classes to xml? Or the other way around? – Killingsworth Oct 10 '13 at 2:42
  • Your question is flawed. I suggest you think about the problem again in light of the Single Responsibility Principle. Creating instances is a different responsibility than storing data is a completely different responsibility from drawing View elements. – Amy Blankenship Oct 10 '13 at 2:55
  • Yes. Database->Classes->XML. – user2865206 Oct 10 '13 at 2:56
1

A partial answer, addressing the core points of your question:

  • Each class will know (have defined by default) the classes that are directly contained within them

A class should know the other classes only to the extent needed for it to do its job. If all you need is generating a XML document that might be as little as a constructor, a loadFromDatabase() method to fill in the fields and a toXML() method to create the XML fragments you will need. Everything else is best kept private, including whatever is needed to make the constructor and the public methods work.

  • Each class will have a process() function that will add itself and its childeren to the XML document we are creating

A better approach would be a Person class (which would correspond to the top level of the desired XML) having a toXML() method which returns the full XML document, doing so by calling the toXML() methods of the children and composing the fragments as appropriate.

0

Some suggestions for building the object graph:

As you said, to populate the objects you'd have to pass a datastructure through the object hierarchy. But this is only true if you build the graph from top to bottom.

A better approach would be to build it from bottom to top using e.g. a factory (the example is written in Java):

public class Person {
    private String name;
    private int age;
    private Address address;
    private List<Relatives> relatives;        

    public Person(String name, int age, Address address, List<Relatives> relatives) {
        this.name = name;
        this.age = age;
        this.address = address;
        this.relatives = relatives;        
    }
}

public class Address {
    String street;
    String city;
    String state;

    public Address(String street, String city, String state) {
        this.street;
        this.city;
        this.state;
    } 
}

public interface Relative {
}

public interface Parent extends Relative {
}

public class Mother implements Parent {
    private String name;

    public Parent(String name) {
        this.name = name;
    }
}

// and some more classes; this is left as an exercise to the reader ;)

public class PersonFactory {
    public static Person newPerson() {
        // create the address       
        Address addr = new Address("100 Main St.", "Sylvania", "OH");
        // create the list of parents
        List<Parent> parents = new List<Parent>();
        parents.add(new Mother("Jane Doe"));
        parents.add(new Father("Jane Doe"));
        List<Sibling> siblings = new List<Siblings>();
        // analogue to parents

        List<Relatives> relatives = new List<Relatives>();
        relatives.add(parents);
        relatives.add(siblings);
        // now create the person and return him

        return new Person("John Doe", 21, addr, relatives);
    }
}

Passing the direct dependencies via the constructor is called dependecy injection. This can be achieved manually (e.g. using factories) or using libaries like Spring or Juice (in Java).

(The PersonFactory's only responsibility is building the object graph).

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service, privacy policy and cookie policy