I have been trying to brush up on my java and wrote a small card game to do so. During this I had some problems while trying to uncouple unrelated parts.
First a motivating example:
Cards can have subtypes like Ammunition. Ammunition can be played directly like normal attack cards or be fired by other cards which causes a different effect.
Cards have to be stored in a homogeneous collection so there has to be some degree of reflection or reification to check for the concrete capabilities of a card. Unrelated parts also have to react to these actions, think
for each ammunition fired this round do X and ideally these events shouldn’t have to be triggered manually.
In summary: It should be possible to add new cards and new subtypes with new actions without having to modify (or ideally even recompile) old code. A card has to be able to implement multiple subtypes. It has to be possible to query at runtime which actions a card supports, to invoke them and to subscribe to action types and be notified whenever one is played.
The simplest solution would be to use interfaces directly and make each card implement the relevant ones. This feels somewhat unsatisfactory, however. It’s possible to check for interfaces via instanceof but intersection types aren’t first class so combining subtypes becomes arduous. Code sharing between similar cards can also become quite verbose and notifications have to be triggered manually which seems like it would cause hard to catch bugs in the long run.
My second idea was to use a heterogeneous map like
IdentityHashMap<Class<?>, Feature> so that implementations could be queried like
Optional<Ammunition> ammo = card.get(Ammunition.class); ammo.ifPresent(impl -> impl.shoot(card, source, target));
but the Ammunition should be able access the members of the card somehow, ideally without unsafe casts. The Ammunition interface can’t be generic over the concrete card type since the type token doesn’t reify type parameters. Adding a reference to the card in Ammunition works but implies a separate heterogeneous map per card instance instead of per card type. Alternatively the instance data could be stored outside of the card object so that cards are basically only unique identifiers which make it possible to query their data and actions.
This seems to work but I noticed that this just sounds like slowly reinventing entity component systems. Since the goal of the project was to play around with OOP that seems kind of counterproductive, though.
So here are my questions:
- Is this even a reasonable thing to want or am I missing a better approach that circumvents this issue?
- Is there a clean (or at least more OOP) approach to solving this?
Thanks for reading and sorry that the text got so long!
✓ Extra quality
ExtraProxies brings the best proxy quality for you with our private and reliable proxies
✓ Extra anonymity
Top level of anonymity and 100% safe proxies – this is what you get with every proxy package
✓ Extra speed
1,ooo mb/s proxy servers speed – we are way better than others – just enjoy our proxies!
USA proxy location
We offer premium quality USA private proxies – the most essential proxies you can ever want from USA
Our proxies have TOP level of anonymity + Elite quality, so you are always safe and secure with your proxies
Use your proxies as much as you want – we have no limits for data transfer and bandwidth, unlimited usage!
Superb fast proxy servers with 1,000 mb/s speed – sit back and enjoy your lightning fast private proxies!
99,9% servers uptime
Alive and working proxies all the time – we are taking care of our servers so you can use them without any problems
No usage restrictions
You have freedom to use your proxies with every software, browser or website you want without restrictions
Perfect for SEO
We are 100% friendly with all SEO tasks as well as internet marketing – feel the power with our proxies
Buy more proxies and get better price – we offer various proxy packages with great deals and discounts
We are working 24/7 to bring the best proxy experience for you – we are glad to help and assist you!