So I got the Address
class:
class Address
{
private String streetAddress;
private int number;
private String postalCode;
private City city;
private State state;
private Country country;
}
And I want to get its readable version to, lets say, show in a grid column.
Whats the best and concise way to implement this?
toString
method inside classAddress
(I personally don't like this approach, as 'toString' is not directly related to an Address)- class
ReadableAddressFormatter
ReadableAddressFormatter
(Address
addressToFormat
)- public
String getFormatted()
- Previous class but
getFormmated
would be static, receiving theAddress
instance and returning the string - Other? Suggestions please.
I'm looking for a good design, focusing also in Clean Code, Decoupling and Maintainability.
You've tagged your post with Java, so I'll answer for Java (and Swing, more specifically). This task is normally the task of a specific TableCellRenderer. If the same format must be used for other visual components, I would indeed extract the formatting inside an instantiatable class (solution 2). This would allow subclasses to customize the format if needed.
Using
toString
requires no additional baggage outside the function itself; seems like the simplest solution. It's there for a reason, right?I think that a
toString()
method that returns a string is your best approach. If you have an Address instance, let's sayaddress
, then it is obvious whataddress.toString()
does. The fact thattoString()
isn't directly associated withAddress
doesn't really change anything..NET SOLUTION:
Overriding
Object.ToString()
seems to be the most logical solution. This makes it clean to use in situations such as:Console.WriteLine("Home Address: {0}", homeAddress);
If you wish to provide additional formatting, the Address class should implement
IFormattable
.Also, you should create an AddressFormatter class that implements from
IFormatProvider
andICustomFormatter
.The MSDN links provide very well put examples (a BinaryFormatter and a AcctNumberFormat), but if those aren't enough also look at this good example: PhoneFormatter
Additionally, if you do decide to go full out on this and implement IFormattable and a custom IFormatProvider/ICustomFormatter then I'd suggest having your ToString() simply call to your ToString(String format, IFormatProvider formatProvider) with a default provider. That way you can account for things like localization and types of addresses (short, long, etc).
Usually i divide presentation layer from data layer. Presenting it to a GUI seems to me something related to the presentation layer, not the data layer.
I would suggest you to put a function somewhere in your presentation layer that will convert the address to string.
Presentation of data is not related to data!
A static method is good. A converter class would be better, you can keep one single instance for your application but you can replace it or write another if you are moving your application from GUI to WEB with another format, or if in one window you want to show everything and in another window you want to show only part of the informations or informations formatted in another way.
There are several model you can follow, for example Microsoft WPF uses totally another approach, the MVVM, Model View View Model, that will allow you to divide very well data layer from business logic from presentation layer.
I usually override ToString in C# or toString in java only for debugging purposes (presenting a string that i can use for debug) or for some kind of simple serialization to string, usually putting also a FromString (or fromString method in java). One example is custom types like Point, Vector, Matrix and so on.
Talking about C# world..
Then in your form (for example).
If you want you can imlpement other useful interfaces like for example ITypeConverter
All of these methods have been used, and there's no way to offer a "context independent" best practice. The best answer in Software Engineering is usually "it depends." That's said, let's analyze each:
Hope this helps, and kudos for thinking about Clean Code, Decoupling, and Maintainability from the beginning.
For an example of principle #2 in action--using the Strategy Pattern, adhering to the Single Responsibility Principle, the Open/Closed Principle and allowing for Inversion of Control via Dependency Injection-- compare the following approach (graciously provided by @SteveJ):
With this one (in "mostly correct" Groovy):
As @SteveJ has observed: