In your simple example, you know exactly the real type of the object on which you invoke the visitor and can therefore chose yourself the right visitor method:
makeSoundVisitor.visitCat(cat); // You know that cat is a Cat
makeSoundVisitor.visitDog(dog); // You know that dog id a Dog
But what if you don't know the type of the object? For example
But I really don't see the point of that accept call. If you've got the visitor and the objects to be visited, why not just pass these objects directly to the visitor and avoid the indirection?
Christophe's answer is on point, I just want to expand on that. Not knowing the runtime type of the object is actually an assumption of the Visitor pattern.
You can ...
Go for option 2 and replace a deeply nested class hierarchy with a lean entity-component-system design.
If you want to know more about why this approach is widely used in the game industry and how to implement it in all details, you may be interested in Mike McShaffry’s excellent book “Game Coding Complete” (if there is still a recent edition).
There's a better option.
You want to separate shop tags from customer tags and you struggle with the fact that they are both just tags. Then why not add another property to tag for differentiation?
In addition to id and name you could introduce type, which is of type TagType. Then create an enum TagType with members Shop and Customer.
or keep a common Tag class despite it has no business sense?
Does not refer to the same business reality
Not all code directly translates to or stems from a business need. If a common class makes sense for a particular code design, then there's nothing wrong with using it. Assuming the design itself is appropriate of course.
Since those two type of tags ...
Like the other answers, I have to admit Christophe's answer is spot on, but there's some confusion around why one might want to getRandomAnimal().
The frustrating reality is that very few books that show the visitor pattern bother showing the most important reason you use it: often the code that constructs your objects knows the real type of the object, but ...
What’s missing in your basic OOP features are not associations, but composition:
object composition is a way to make more complex object structures
object composition can often be a better alternative for inheritance (i.e. prefer composition over inheritance)
object composition can be used to implement associations
Every OOP languages provides composition....
This seems like a good use case for a generic type. You can define a type Tag<T>, and then where relevant code that deals with tags depend specifically on Tag<Shop> or Tag<Customer>, without you needing to create those two separate classes.
These two approaches look similar in surface but have some important differences:
option 1: A and B can have completely independent behaviors. B may reuse some behavior of A without outside world knowing.
option 2: B and A can have potentially independent behavior, although the naming strategy suggests that A’s behavior is influenced by B. A also exposes B’...
A state is defined very broadly in UML as:
A State models a situation in the execution of a StateMachine Behavior
during which some invariant condition holds.
To make it more practical, imagine that a state corresponds to the machine waiting for some things to happen, and when they happen the machine may change its state.
Here there are clearly several ...
Never say never. Unless it’s impossible.
I could very easily imagine that your system, may one day manage Purchase of those customers in those shops. What bout the new PurchaseTag? Should it be yet another independent transaction related tag entered by the user? Or could it be automatically assigned by the system for example based on the most expensive ...
It's easier to lump splits than to split lumps. There are at least two different possibilities for the future evolution of this code:
The tags stay split apart forever
The tags need to be merged.
If they are separate, then in case 1, you're happy since nothing needs to be done. In case 2, you can just rename ont of the two tags, say ShopTag to Tag, remove ...
Increasing cohesion could theoretically reduce coupling in a system, but it won't in all cases.
These two quantities are not exact opposites as some imagine. For example, Patel et al say, "Information hiding seeks to minimize connections (coupling) between two different components while cohesion seeks to maximize connections within a component." [Sukesh ...