Note that there are some explanatory texts on larger screens.

plurals
  1. PO
    text
    copied!<p>I don't think i would go with a visitor. That would be appropriate if you don't know at design time, what operations you need to perform on it later, so you open up the class to allow for others to write visitors that implement that logic. Or there are so many things that you need to do on it that you don't want to clutter your class with this. </p> <p>What you want to do here is create an instance of a class from a DTO. Since the structure of the class and the DTO are closely linked (you do your mapping in the DB, I assume you handle all mapping issues on that side and have a DTO format that maps directly to the structure of your customer), you know at design time what you need to. There's no need for much flexibility. (You want to be robust though, that the code can handle changes to the DTO, like new fields, without throwing exceptions)</p> <p>Basically you want to construct a Customer from a snippet of a DTO. What format do you have, just XML or something else? </p> <p>I think I would just go for a constructor that accepts the DTO and returns a Customer (example for XML:)</p> <pre><code>class Customer { public Customer(XmlNode sourceNode) { // logic goes here } } </code></pre> <p>The Customer class can 'wrap around' an instance of the DTO and 'become one'. This allows you to very naturally project an instance of your DTO into a customer instance:</p> <pre><code>var c = new Customer(xCustomerNode) </code></pre> <p>This handles the high level pattern choice. Do you agree so far? Here's a stab at the specific issue you mention with trying to pass properties 'by ref'.I do see how DRY and KISS can be at odds there, but I would try not to overthink it. A pretty straight forward solution could fix that.</p> <p>So for the PostalAddress, it would have it's own constructor too, just like the Customer itself:</p> <pre><code>public PostalAddress(XmlNode sourceNode){ // here it reads the content into a PostalAddress } </code></pre> <p>on the customer:</p> <pre><code>var adr = new PostalAddress(xAddressNode); </code></pre> <p>The problem I see here is, where do you put the code that figures out if this if the InvoiceAddress or the HomeAddress? This does not belong in the constructor of the PostalAddress, because there could be other uses for the PostalAddress later, you don't want to hardcode it in the PostalAddress class. </p> <p>So that task should be handled in the Customer class. This is where he usage of the PostalAddress is determined. It needs to be able to tell from the returned Address what type of address it is. I guess the simplest approach would be to just add a property on PostalAddress that tells us:</p> <pre><code>public class PostalAddress{ public string AdressUsage{get;set;} // this gets set in the constructor } </code></pre> <p>and in the DTO just specify it:</p> <pre><code>&lt;PostalAddress usage="HomeAddress" city="Amsterdam" street="Dam"/&gt; </code></pre> <p>Then you can look at it in the Customer class and 'stick it' in the right property:</p> <pre><code>var adr = new PostalAddress(xAddressNode); switch(adr.AddressUsage){ case "HomeAddress": this.HomeAddress = adr; break; case "PostalAddress": this.PostalAddress = adr; break; default: throw new Exception("Unknown address usage"); } </code></pre> <p>A simple attribute that tells the Customer what type of address it is would be enough I guess. </p> <p>How does it sound so far? Code below puts it all together. </p> <pre><code>class Customer { public Customer(XmlNode sourceNode) { // loop over attributes to get the simple stuff out foreach (XmlAttribute att in sourceNode.Attributes) { // assign simpel stuff } // loop over child nodes and extract info foreach (XmlNode childNode in sourceNode.ChildNodes) { switch (childNode.Name) { case "PostalAddress": // here we find an address, so handle that var adr = new PostalAddress(childNode); switch (adr.AddressUsage) { // now find out what address we just got and assign appropriately case "HomeAddress": this.HomeAddress = adr; break; case "InvoiceAddress": this.InvoiceAddress = adr; break; default: throw new Exception("Unknown address usage"); } break; // other stuff like phone numbers can be handeled the same way default: break; } } } PostalAddress HomeAddress { get; private set; } PostalAddress InvoiceAddress { get; private set; } Name Name { get; private set; } } class PostalAddress { public PostalAddress(XmlNode sourceNode) { foreach (XmlAttribute att in sourceNode.Attributes) { switch (att.Name) { case "AddressUsage": this.AddressUsage = att.Value; break; // other properties go here... } } } public string AddressUsage { get; set; } } class Name { public string First { get; set; } public string Middle { get; set; } public string Last { get; set; } } </code></pre> <p>and a snippet of XML. You haven't said anything about your DTO format, would work for other formats too. </p> <pre><code>&lt;Customer&gt; &lt;PostalAddress addressUsage="HomeAddress" city="Heresville" street="Janestreet" number="5"/&gt; &lt;PostalAddress addressUsage="InvoiceAddress" city="Theresville" street="Hankstreet" number="10"/&gt; &lt;/Customer&gt; </code></pre> <p>Regards,</p> <p>Gert-Jan</p>
 

Querying!

 
Guidance

SQuiL has stopped working due to an internal error.

If you are curious you may find further information in the browser console, which is accessible through the devtools (F12).

Reload