6

I have long experience in procedural world and been programming/maintaining OO code in various languages too. Now getting into OO design and feeling the pains of identifying objects from scratch. Been reading several books, articles, etc. on OO. Often times they stop with Person, Employee examples. Identifying and doing it the right way in a real world projects raises several questions.

This is sort of a follow up question from my earlier design review question. Say, I have an object like below:

public class AddressRecord {
  protected long RecordID;
  protected String AddressLine1;
  protected String AddressLine2;
  protected String City;
  protected String State;
  protected String PostalCode;
  protected String Country;
  protected String FirstName;
  protected String LastName;
  protected String FullName;
  protected String PhoneNumber;
  protected String EmailAddress;
  protected String CompanyName;
  ..
  /* related to my question below */
  public String extractXml() {}
  public HashMap extractHash() {}
  public String extractJson() {}
  ...
}

Now, I want to extract the field/values into a hashtable or a XML (proprietary format) or JSON structure without resorting to any libraries like JAXB. I will write some methods (for e.g., extractXml, extrachHash, extractJson) to extract specific fields into the target format.

My question is where should such extraction/conversion methods be? Based on some exposure to OO design books and advice, I was assuming I could have these methods right inside this class.

@Vladislav mentioned that they should actually be outside, like in the controller. I kind of get it, but I am curious to know why? Also, if I want to isolate this extraction logic from the controller code, can I create a class doing just that? Like,

public class AddressRecordXml {

   public static String extractXml(AddressRecord rec)
   {

   }

   ...
}

and then use it in the controller as,

...
AddressRecord rec = new AddressRecord();
String xmlStr = AddressRecordXml(rec);
...
String resp = transport.process(xmlStr);
...

Note: I know there are libraries like JAXB etc to help serialize objects to XML etc. I cannot use those, yet. I am working with Java 1.4 inside an old Sybase EAServer (main programming language being PowerBuilder) and it puts a lots of restrictions. Same reason for HashMap, no Generics etc.

  • 2
    Incidentally, these kinds of methods are conventionally named toXxx. – Kevin Krumwiede Nov 21 '15 at 3:55
  • like toXml, toJson? got it, thanks! – SamV Nov 21 '15 at 21:18
2

The OO examples tend to stop with Person, Employee because their goal is to demonstrate the principle of modeling real-world entities. Of course, these entities are fairly pointless on their own: in order to do anything useful with them you will need to use them within some greater system, and designing such a system in an OO way is not easy to describe in terms of simple, easy to swallow examples.

There is no clear cut answer to the question of where these methods should go. A purist might say that the xml extraction method should go into some kind of manager which deals specifically with xml, and which is only included in a system which deals with xml. So, a different system, which would not be dealing with xml, would not include any xml generation code. Also, yet a different system, which would require a different xml representation, would only include code dealing with that representation, instead of being complicated with one default and unused xml extraction routine in the data object and a different xml extraction routine elsewhere.

But of course that's highly academic. Putting the xml extraction routine in the data object is a fine pragmatic compromise, which keeps things simple right from the beginning, and if you ever encounter the need for a different system configuration, you can easily refactor it out of the data object and into some manager.

Note 1: The current trend is to avoid calling things "managers". So they call them "controllers" instead. That's actually laughable.

Note 2: I really hope you have significant monetary compensation for the unhealthy occupational conditions of having to work with java 1.4; if not, please do consider leaving that job. Personally, I would not even consider any version of java prior to 1.8.

  • 1
    thanks for the reply. lol about compensation. This application is mainly a n-tier PowerBuilder application that needs Java programs for inner workings. Unfortunately, it being old, I have to band-aid constantly. I Trying hard to get more into Java. I do get to work on upto Java 1.6 in other tasks. Hopefully one day, I can demand newer versions and better compensation :) – SamV Nov 20 '15 at 23:31
2

As the OP has correctly surmised, sometimes OO is just OO for OO's sake. You see this "antipattern" every time you see a "util" package. aaaaannnd....they're in EVERY project. Sometimes it just makes sense to extract common mundane static-ish functions into collections of utils, that bear a striking resemblance to functional programming. If it's not labeled "util" it is probably labeled "helper."

Also, I cringe a bit when people eschew using library code for this stuff...what part of "this code has undergone 500,000 hours of unit testing in the user community" is not appealing to you?

  • Thank you @dwoz. I would love to use libraries where possible. Right now, I am using Apache Axis libraries for WSDL and Apache HttpClient for Http requests. But, my hands are tied because of the "old" setup. I cannot even use annotations and generics in Java 1.4, I have to code in. Frustrating. And even more frustrating for me diving deper into the Java world, is the amount of options available. Which one do I use for a specific task? but thanks again for your feedback. – SamV Nov 21 '15 at 0:25
2

I was assuming I could have these methods right inside this class, but ... mentioned that they should actually be outside, like in the controller.

Both designs are possible, and which one is better suited to your case, depends. For smaller programs, with only a handful of data objects, where you only need one conversion function like extractXml and none of the others, you may decide to put this function directly into the class. When your program becomes bigger, and your class AddressRecord might have several other functions, putting functions like extractXml or extractJson into a separate class like AddressRecordXml will help you to give your program more structure, and to keep your AddressRecord more universal.

However, when you have a lot of such data classes, your design will really improve if you can implement a generic version of extractXml(object), not specificially a method of AdressRecordXml, but of a universal class like XmlExtractor. Even in Java 1.4, there is reflection available, which will allow you to implement such a class in a generic way.

To your comment: when you start with a small program, you might place extractXml into AddressRecord directly. When your program grows over time, you need to refactor any parts of the code into separate classes which become otherwise "too complex". The trick is not to miss the point when to refactor, and to start with that as soon as your code starts to violate the SOLID principles. That is IMHO the only way to deal with "the future" correctly - creating a design for "the future" without knowing the future always leads to wrong design decisions.

  • thanks for the reply. When I try to Google for some samples, I get so many variations of such implementations. Now I see why. So, it really depends on the size of the project? Should I worry about what could happen to the classes in the future (that's part of my struggle) or just design for right now? – SamV Nov 20 '15 at 23:42
  • 1
    "Worry"? no. "Think about"? sure, why not. "Design for now"? definitely. Well focused classes - adherence to single responsibility principle - lends itself to change. You already have your re-usable bare-bones DTO. If you know change is definite, think about the adapter concept; I don't say "pattern" here because I want to emphasize that patterns are not always full-blow, all or nothing things; first, they are concepts. Something as simple as a delegate. – radarbob Nov 21 '15 at 2:05
  • 1
    .. cont. ... Maybe a class that takes a delegate and an AddressRecord. You could say that is the command pattern concept even. It's about how to think about the problem, not a rigid class design in the GOF book.. Let me be clear: do not over-design for the unknown. P.S. If you start thinking "But.. what about Open/Close Principle?" Don't worry. I have a coupon for a free lobotomy. – radarbob Nov 21 '15 at 3:04
  • I partly agree to the YAGNI-strategy of lesser abstraction, not abstracting extractxml away. But on the other hand: let's be honest - who really refactors the code later? Most of the time such knowingly sloppiness is the starting point of technical debt. Over time requirements change and more and more code is added under pressure with the "next time I'll clean up - I have no time now" in mind. I find it much easier to make such small abstractions up front - even though it might seem overengineering. But it will pay off later, And even with YAGNI it doesn't hurt much. – Thomas Junk Nov 21 '15 at 22:43
1

It depends on the complexity, but I would usually create one or more input/output classes.

I would typically create an AddressRecordInput interface that provides a read() method that returns an AddressRecord and an AddressRecordOutput interface that provides a write(AddressRecord) method. I would then provide implementations of these interfaces, such as AddressRecordXMLInput, AddressRecordXMLOutput, AddressRecordJSONInput, and AddressRecordJSONOutput, each with an appropriate constructor. For the constructor, I would consider some kind of existing reader, writer, or IO stream.

I would repeat this for every of your data models classes. These IO classes can leverage third-party libraries, such as JAXB (for XML) or Apache POI (for IO to and from Microsoft Office formats).

The downside is that for large data models, there are a lot of classes. However, they tend to be easy to understand and test.

1

There is a clear separation of concerns:

1) You have your Data (DTO) AddressRecord

2) You have the need for representing the model in several ways

That said, there are (at least) two objects needed: (1) the DTO itself (2) an output module

The typical/orthodox OO way of implementing this is via strategy pattern. The mechanism of handling the different outputformats is abstracted away in an interface implementation - for the sake of the example, let's name it AddressWriter, with one simple method write(). The concrete implementation of the interface encapsules the mechanism. The machanism of extraction, converting to JSON/XML whatever is paced there. The DTO doesn't need to know of JSON or XML, nor does it have to know which values are for which format interesting. It is not its concern.
The advantage is clear: By abstraction ou gain freedom to implement different formats without changing or breaking existing code: You only need another mechanism implementation.

You could call it highly acamdemic - I call it proper design.

  • Thank you, @Thomas. Been maintaining or enhancing other people's design in Java - Stored procs, programs, JSP, WS clients etc. Now, I got an opportunity to do it properly, and is what I want to do. Without changing or breaking our existing legacy code is what I have to do. After hours of online courses, youtube, books, articles, I "understand" the patterns, OO etc in the context of Animal <- Dog, Cat etc :). Struggle a bit when it's XML writer etc; your answer sorta clears it up for me. If you don't mind, can you pls. elaborate on how you arrive at Strategy pattern for this? Thanks. – SamV Nov 23 '15 at 1:27
  • 1
    There are two ways to supply objects with behaviour: (1) Inheritance - where you have a group/family of similar objects. (2) Composition - you compose objects from other objects. If you chose (2) you implement to an interface, which means nothing more than: you expect to behave a component in a certain way; you want something which does something for you, independent of what it is. If you abstract the description of behaviour in that way, you are implementing a strategy: relying on behaviour of an (exchangeable) external component. You define a contract (=interface) for the behaviour. – Thomas Junk Nov 23 '15 at 10:23

Your Answer

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

Not the answer you're looking for? Browse other questions tagged or ask your own question.