• Post Reply Bookmark Topic Watch Topic
  • New Topic
programming forums Java Mobile Certification Databases Caching Books Engineering Micro Controllers OS Languages Paradigms IDEs Build Tools Frameworks Application Servers Open Source This Site Careers Other all forums
this forum made possible by our volunteer staff, including ...
Marshals:
  • Campbell Ritchie
  • Devaka Cooray
  • Liutauras Vilda
  • Jeanne Boyarsky
  • Bear Bibeault
Sheriffs:
  • Paul Clapham
  • Knute Snortum
  • Rob Spoor
Saloon Keepers:
  • Tim Moores
  • Ron McLeod
  • Piet Souris
  • Stephan van Hulst
  • Carey Brown
Bartenders:
  • Tim Holloway
  • Frits Walraven
  • Ganesh Patekar

Finding the best approach to resolve a Java class problem design

 
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hi!
I am posting a new topic ,so you can understand my problem with a real approach.

Lets see:
I am requesting data to 3 or more providers.
Each provider represent an Api ,which returns data for different things.
Example :
http://providerOne/getAvailableSlots
http://providerOne/getLastSlots
......(A lot more signatures)

http://providerTwo/getAvailableSlots
http://providerTwo/getLastSlots
......(A lot more signatures)

Both providers,returns same data structure for getAvailableSlots (name,lastName,age) ,and the same dataStructure getLastSlots(hour,minutes,seconds)
(I have mucho more providers,but you get the idea)

I have an special provider which is:

http://specialProvider/getAvailableSlots
http://specialProvider/getLastSlots

where the return of getAvailableSlots and getLastSlots,it s diferrent from the others providers.
---------------------------------------------------------------------------------------------------------------
I am doing a simple class approach to show you the example.The real proyect it s using Spring boot , and rest template to make the request.

Here a class that represent the Response related to AvailableSlots

Here a class that represent the Response related to LastSlots


(...and so on,i will have one abstract class for each kind of response)

Now,a concrete Response for Available Slots (Almost all providers return this structure for this request)

Now ,remember i have a special provider where the response it s different from the other:

Ok,now when i get the response,depending on the provider who sent the data,i need to do some kind of transformation with the data,if data came from ProviderOne maybe i do someting ,if data came from
ProviderTwo i would like to do another thing,etc.So i have:


First of all,how to avoid casting in the above interfaces??

After doing of those classes,i will add a Client to test the code and show my problem:



All this code it s for asking,how to avoid casting on each provider?What am i missing here?
Just think for a minute,if a have to cast each response,maybe i will have a lot of getResponse(SomeResponse resp) and a lot of interfaces and i dont want to do casting for all the app.I know i am missing something,
so i can do a better desing.
One thing,i dont want to make a generic interface ,because like i told you above,i am gonna have a lot of getResponse on the interface,and i want to avoid to pass a lot of classes in the class implementing the interface:


I really appreciate any help !! Thanks in advance guys!
 
Saloon Keeper
Posts: 10407
223
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Yes, the design is off.

Depending on how specific the operations are that you want to perform on the responses, you can go with two approaches:

1) Make a business model that encapsulates all the properties that you need that all responses contain in some form, and make the response itself responsible for transforming itself to an instance of the business model. This is the easier approach, and preferable if this provides enough flexibility for your purposes.

2) Make separate classes for each response that you need to perform special processing on, and then let those classes perform the special operations using the visitor pattern. While it provides more flexibility, it's also more complex.

In either case, make data transfer object classes for each provider and make them responsible only for representing the data that you get from those providers. Here's an example that uses JAXB:

If we take the first approach, we have one model class that encapsulates all the stuff you're interested in:

We add a method to the data transfer object that converts it to an instance of the model:

Now, regardless of the format of the data that you get from each provider, the responses are able to convert themselves to a uniform model, which you can then operate on without using special cases.

If we take the second approach, you would make separate model types that have a common interface that accepts a visitor:

Now, we can implement specialized operations by implementing a visitor:

This works with references to the supertype, without casting:
 
Rancher
Posts: 460
6
IntelliJ IDE Spring Fedora
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
In the case of the design which uses a visitor pattern, is the business logic done through the visitor?
Like



I feel like you would do the visitor pattern when you aren't sure if you want to be set on one particular business model object. If you want to do use the data in a different model object then it would be easier to add the functionality to a new visitor instead of adding a bunch more toWhatever() methods.
 
Stephan van Hulst
Saloon Keeper
Posts: 10407
223
  • Likes 1
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Almost, but not quite.

You use the visitor pattern when you have operations that need to be implemented slightly differently for different types, but you either can't implement the operation inside those different types, or you can't call it without casting because the types don't have a common interface where you can call the operation on.

The example in this thread doesn't really fit, because both types of Person can be made to fit in a common interface that has a method that returns the full name, or you can in fact use the same class for both situations as I demonstrated with my first approach. However, there might be properties and operations that Coi hasn't told us about that don't fit the first approach so neatly.

A better example would be a shape editor application. Let's say you have buttons to add different kinds of shapes to a canvas, such as polygons, Bézier curves, etc. So you have a Shape base type and several subtypes that extends Shape.

Now, imagine that after making an image using these shapes, you want to save the shapes to disk in a certain format. You could do the following:

This has some big drawbacks. Firstly, you're cluttering your Shape API with all kinds of methods that are unrelated to editing shapes. Secondly, you can't easily add new file formats without changing your Shape API, possibly breaking backward compatibility.

We could also do the following:

We now have a simpler API, but it has other drawbacks: Firstly, implementations of the save() method are now responsible for converting the shape to the binary data that is appropriate for the given format. This is potentially a very difficult task, one that in our previous iteration of Shape was handed by classes such as XmlStreamWriter and PdfWriter.

Secondly, implementations are ugly and hard to maintain:

The solution here is to allow shapes to be visited, and have different save operations implement a visitor:

Now, not only have we extracted all of the save logic from the various Shape subclasses, we have a class per file format that tidily encapsulates the logic for saving to that specific file format AND we can use the visitor to implement different operations that don't even have anything to do with saving shapes, such as transforming shapes to different shapes. If a new file format is added, we just create another ShapeVisitor implementation to represent that save operation. If we add a new shape, which is not expected to occur frequently, we can add another method to the ShapeVisitor interface, and our compiler will tell us that we have to implement that method on all our existing save operations, so we don't forget to save the new shape.
 
Coi Saurus
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Stephan van Hulst wrote:Almost, but not quite.

.



I really appreciate your time ,and the way you explain things.
I am trying to se how to fix everything with my problem,i will rewrite the code using this patter to see if i am getting the idea.
And what you told to the other user is true,i didnt give you all the information ,just to explain my problem in a most simple way.
Thanks!
I will answer again as soon i can write a little code using your approach !
 
Coi Saurus
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
Hey Stephan van Hulst!
After you talked to me about the visitor pattern,i been researching a little bit.i will show you my code now ,anyway it seems i still have the same problem.
One important thing!
I cant have a class where i can group all responses for each provider.Example,response for the same subject (getAvailableSlots for example) ,on each provider could came with the same data with same name but with different data Type. Example ,age,could be an int for all providers and String for the special provider,but the field it has the same name 'age',so thats why i need to have 2 group of classes for providers.
One group of class to hold the data from all providers request(getAvaialbeSlots,getAnotherThing,etcetc) ,and one group of Classes to hold the data of the same requests but from this 'Special Provider'.

Here is the code implementing the Visitor Patern :


Now the concrete responses:

The Visitor interface:

Now implementing concrete visitors (The transformers):

And here the client,using the this approach:


I really like this approach,but as you can see i cant avoid of casting on each visitor to the concrete TypeOfResponse,because the Visitor interface 'visit' a ResponseType,not a concretion.
Am i implemeting the patter in a good way or i am faling?
Thanks again!
 
Al Hobbs
Rancher
Posts: 460
6
IntelliJ IDE Spring Fedora
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
You mention casting.  You could just add another another method to the visitor that accepts ConcreteA or SpecialConcreteA.  The purpose of the visitor is to allow flexibility with different types of implementations for different data types.  
 
Coi Saurus
Greenhorn
Posts: 6
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Al Hobbs wrote:You mention casting.  You could just add another another method to the visitor that accepts ConcreteA or SpecialConcreteA.  The purpose of the visitor is to allow flexibility with different types of implementations for different data types.  


The problem it s that doing what,i should add that at the Interface level:

Doing that ,i am forced to implement   void visit(ConcreteA  concreteAResponse) or void visit(SpecialConcreteA specialAResponse); ,in classes where i just need to give an implementation to just ONE of both.
So will need to leave an empty metod always:

Thank you guys!
 
Al Hobbs
Rancher
Posts: 460
6
IntelliJ IDE Spring Fedora
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator
If you only need one implementation  for both why are you casting?
 
Stephan van Hulst
Saloon Keeper
Posts: 10407
223
  • Mark post as helpful
  • send pies
  • Quote
  • Report post to moderator

Coi Saurus wrote:


No, don't do this. Have ONE visitor object that implements the different operations for the different concrete subtypes. Then you pass it to the visit() method that is declared in an interface that ALL response types implement. The appropriate operation will then be called for the appropriate subtype.

i cant avoid of casting on each visitor to the concrete TypeOfResponse,because the Visitor interface 'visit' a ResponseType,not a concretion.


As Al said, you would then add an overload for the concrete subtype to your Visitor interface. I still find it very questionable though, that you have such different operations for concrete sub-types. It just reeks of bad design. What are these operations that have to be so different for ConcreteReponseA and SpecialConcreteResponseA that you can come up with a generic algorithm that fits both? It suggests to me you are not properly separating your data-layer and your business-layer.

Coi Saurus wrote:Doing that ,i am forced to implement [...] in classes where i just need to give an implementation to just ONE of both.


You can elegantly solve this by writing an adapter class:

You can then easily implement operations for just one subtype:


Let me reiterate though. I don't know why you would want to use the visitor pattern on classes that represent responses from some external services. If the services return similar data, then why can't you create a uniform model? If the services return data that represent completely different things, then why are you handling those different things in the same piece of code?
 
Too many men are afraid of being fools - Henry Ford. Foolish tiny ad:
Java Code Review and Psychology
https://coderanch.com/t/714798/java/Java-Code-Review-Psychology
  • Post Reply Bookmark Topic Watch Topic
  • New Topic
Boost this thread!