GameObjects and Code Structure - java

I have the following GameObject interface:
public interface GameObject {
void viewDetails();
}
Character Interface:
interface Character{
void pickUp(Weapon weapon);
void use(Weapon weapon);
}
and abstract Weapon class:
public abstract class Weapon implements GameObject {
//left out constructor to focus on methods
#Override
public abstract void viewDetails();
public abstract void attack(Enemy enemyObj);
//Could be bullets, could be a mystical item.
public abstract void replenish(ReplenishItem rpItem);
}
The problem with this is, a GameObject sometimes can be used in different ways.
For example, the primary use of a game weapon is to attack a target, but what if I wanted to reload? How do I let my character interface reload or beware that reload is an option?

I would use the following approach.
I would declare interfaces:
interface MeleeWeapon {
void hit();
void cut();
}
interface FirearmWeapon {
void fire();
void reload();
}
interface MagicWeapon {
void throw();
void apply();
void recharge();
}
Then implement classes, like these:
class Knife implements MeleeWeapon {
public void hit() {
}
public void cut() {
}
}
class Dagger implements MeleeWeapon {
public void hit() {
}
public void cut() {
}
}
class GarandRifle implements FirearmWeapon {
public void fire() {
}
public void reload() {
}
}
class Fireball implements MagicWeapon {
public void throw() {
}
public void apply() {
}
public void recharge() {
}
}
Then, I would declare these interfaces:
interface MeleeWeaponUser {
void use(MeleeWeapon weapon);
}
interface FirearmWeaponUser {
void use(FirearmWeapon weapon);
}
interface MagicWeaponUser {
void use(MagicWeapon weapon);
}
And, I would declare character classes:
class Peasant implements MeleeWeaponUser {
public void use(MeleeWeapon weapon) {
}
}
class Marine implements MeleeWeaponUser, FirearmWeaponUser {
public void use(FirearmWeapon weapon) {
}
public void use(MeleeWeapon weapon) {
}
}
class Sorcerer implements MeleeWeaponUser, MagicWeaponUser {
public void use(MeleeWeapon weapon) {
}
public void use(MagicWeapon weapon) {
}
}
This approach let us add new weapons and characters without sufficient effort later.
In your use() method you can call reload() if there is no more ammo in the weapon dispenser.
But if your game character receives signal from outside, for example, reload the gun, even there is enough ammo to fire, then have an Event->Listener approach implemented.
Create a WeaponEvent class, extend this class to have FirearmWeaponEvent, MeleeWeaponEvent etc.
Make your game character class(es) as a listener to WeaponEvent events, then in your game character class have a method processEvent(WeaponEvent event), and act accordingly to the event you have received.

Related

Abstract method with different parameters Java

public abstract class CommonClass {
abstract void send(<what should i put here???>) {}
}
public class ClassA extends CommonClass {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass {
void send(List<Post> postList) {
// do stuff
}
}
I am new to OODP, I am trying to have a method that is able to take in any kind of List data so that I can abstract things out. How can i do this?
You could make it generic on some type T. Like,
public abstract class CommonClass<T> {
abstract void send(List<T> al);
}
And then, to implement it - use the generic. Like,
public class ClassA extends CommonClass<Comments> {
#Override
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
Also, as discussed in the comments, your class names could be improved to be more intuitive; something like,
public abstract class AbstractSender<T> {
abstract void send(List<T> al);
}
and then
public class CommentSender extends AbstractSender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender extends AbstractSender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
That has the advantage(s) of being more readable and easier to reason about (I can tell what a PostSender does by reading the name, ClassB not so much).
Finally, this looks like a case where an interface would work since your abstract class is purely virtual (and should be preferred since you can implement multiple interface, but can only extend from a single parent class);
public interface ISender<T> {
void send(List<T> al);
}
public class CommentSender implements ISender<Comment> {
#Override
void send(List<Comment> commentsList) {
// do stuff
}
}
public class PostSender implements ISender<Post> {
#Override
void send(List<Post> postList) {
// do stuff
}
}
In order to achieve this, you can take multiple approaches, I would suggest looking into Generics: https://docs.oracle.com/javase/tutorial/java/generics/index.html
With that said, there is one approach that is the most elegant and simple: you can supply a List<T> where T is a generic type.
public abstract class CommonClass<T> {
abstract void send(List<T>) {}
}
public class ClassA extends CommonClass<Comment> {
void send(List<Comments> commentsList) {
// do stuff
}
}
public class ClassB extends CommonClass<Post> {
void send(List<Post> postList) {
// do stuff
}
}
You can do that with the help of generics. https://www.tutorialspoint.com/java/java_generics.htm
Example
The abstract class
public abstract class CommonClass {
public abstract <T> void send(List<T> data);
}
Its child
public class Child extends CommonClass {
public <T> void send(List<T> data) {
// code here
}
}
Retrieving the list's contents
Retrieving the generified list's contents is similar to retrieving any list's contents. In the scope of the method, "T" is a type of object contained in the list.
for (T t : data) {
// to check if t is a string
if (t instanceof String) {
// code
}
}
You can also use lambdas to retrieve every element in the list.

Deduce derived types polymorphically

Whats the recommended design approach/alternative to the situation below:
BaseCalculator:
BaseType prepareData()
useData(BaseType)
Derived calculators use derived type to override base functionality -
DerivedCalculator1:
BaseType prepareData(){ return DerivedType1}
useData(BaseType t1){ DerivedType1 t=(DerivedType1)t1 //typecast down and proceed....}
DerivedCalculator2
BaseType prepareData(){ return DerivedType2}
useData(BaseType t1){ DerivedType2 t=(DerivedType2)t1 //typecast down and proceed....}
Is there a design approach to avoid typecasting by the derived classes - as it always leaves the gate open for a run-time mishap?
One alternative is to move the polymorphic behavior into the implementations of the BaseType rather than in the implementations of BaseCalculator. For example:
public interface BaseType {
public void process(Calculator calc);
}
public class DerivedType1 implements BaseType {
#Override
public void process(Calculator calc) {
// Do something specific to derived type 1
}
}
public class DerivedType2 implements BaseType {
#Override
public void process(Calculator calc) {
// Do something specific to derived type 2
}
}
public class Calculator {
public void doSomething(BaseType bt) {
bt.process(this);
}
}
If that type of solution is insufficient, a more complex solution is the Visitor Pattern. The Visitor Pattern allows any arbitrary BaseType object to be handled by any arbitrary BaseCalculator using double-dispatch. The catch is that all BaseCalculator implementations must have an method to handle each of the BaseType implementations. For example:
public interface BaseType {
public void process(Calculator calc);
}
public class DerivedType1 implements BaseType {
#Override
public void process(Calculator calc) {
// Do something specific to derived type 1
}
}
public class DerivedType2 implements BaseType {
#Override
public void process(Calculator calc) {
// Do something specific to derived type 2
}
}
public interface BaseCalculator {
public void handle(DerivedType1 dt);
public void handle(DerivedType2 dt);
}
public class DerviedCalculator1 implements BaseCalculator {
#Override
public void handle(DerivedType1 dt) {
dt.process(this);
}
#Override
public void handle(DerivedType2 dt) {
dt.process(this);
}
}
public class DerviedCalculator2 implements BaseCalculator {
#Override
public void handle(DerivedType1 dt) {
dt.process(this);
}
#Override
public void handle(DerivedType2 dt) {
dt.process(this);
}
}

How to use a parameter of type `Derived` in a overridden method accepting `Base`?

I have the following situation:
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
}
class DerivedA extends Base {
void DerivedBMethodA() {
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something {
void doSomething(DerivedA deriv);
}
}
class DerivedB extends Base {
void DerivedMethodB() {
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new DerivedA.Something() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
});
}
}
I want to push usefulMethod and Something upto the Base class so that DerivedB can leverage it. And I want implementations of Something.doSomething to be able to use a derived type, so that it can access derived functionality.
How do I do that?
Attempts
I've tried the following:
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something {
void doSomething(Base deriv);
}
}
class DerivedA extends Base {
void DerivedBMethodA() {
}
}
class DerivedB extends Base {
void DerivedMethodB() {
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new Base.Something() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
});
}
}
but that fails as my anonymous Something doesn't implement doSomething(Base). So trying to use generics:
I tried:
interface Something {
void doSomething(<? extends Base> deriv);
}
but that won't compile due to: "Wildcards may be used only as reference parameters"
I tried:
interface Something {
<T extends Base> void doSomething(T deriv);
}
but that requires me to implement the interface as so:
a.usefulMethod(new Base.Something() {
#Override
public <T extends Base> void doSomething(T deriv) {
}
});
which obviously doesn't allow me access to the derived type?
There are ways I can make it "work" but they're undesirable:
This:
interface Something {
void doSomething(Base deriv);
}
a.usefulMethod(new Base.Something() {
#Override
public void doSomething(Base deriv) {
DerivedA a1 = (DerivedA) deriv;
a1.DerivedBMethodA();
}
});
But that requires me to cast in each implementation, which seems wasteful.
And this:
package com.miurasample.ui.info;
abstract class Base {
int data = 0;
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something something) {
something.doSomething(this);
}
interface Something<T extends Base> {
void doSomething(T deriv);
}
}
public class Temp {
public static void main() {
DerivedA a = new DerivedA();
a.usefulMethod(new Base.Something<DerivedA>() {
#Override
public void doSomething(DerivedA deriv) {
}
});
}
}
but that results in a warning/IDE highlight in usefulMethod of:
"Unchecked call to doSomething(T) as a member of raw type Base.Something"
What's the tersest and "cleanest" way to do this? Is that I'm doing even sane?
It is difficult to say if your design is wrong or not. We dont have full scope of your requirements to assert that, but here is clean non cast approach to what you are trying to do. It does require extra method in your derived classes:
public static void main(String... args) {
DerivedA a = new DerivedA();
a.usefulMethod( new Base.Something<DerivedA>() {
#Override
public void doSomething(DerivedA deriv) {
deriv.DerivedBMethodA();
}
} );
}
public abstract static class Base< T extends Base<T> > {
int data = 0;
protected abstract T getThis();
void baseMethod() {
System.out.println("baseMethod:" + data);
}
void usefulMethod(Something<T> something) {
something.doSomething( getThis() );
}
interface Something< T extends Base<T> > {
void doSomething(T deriv);
}
}
public static class DerivedA extends Base<DerivedA> {
protected DerivedA getThis(){
return this;
}
void DerivedBMethodA() {}
}
public static class DerivedB extends Base<DerivedB> {
protected DerivedB getThis(){
return this;
}
void DerivedMethodB() {}
}

Why is an infinite loop not caused by Java double dispatch?

In lectures we were shown this code and told that it creates double dispatch but why does it not create an infinite loop?
If c3po.greet(c4po); calls the TranslationRobot method from TranslationRobot
Why does c5po.greet(c4po); call the AbstractRobot method in CarrierRobot and not the TranslationRobot method and then not call the AbstractRobot method in TranslationRobot which would then call the Abstract Method in CarrierRobot and so on?
What decides whether it calls an AbstractRobot method or not?
AbstractRobot.java
abstract class AbstractRobot extends Robot {
abstract void greet(AbstractRobot other);
abstract void greet(TranslationRobot other);
abstract void greet(CarrierRobot other);
}
CarrierRobot.Java
class CarrierRobot extends AbstractRobot {
...
void greet(TranslationRobot other) {
talk("'Hello from a TranslationRobot to a CarrierRobot.'"); }
void greet(CarrierRobot other) {
talk("'Hello from a CarrierRobot to another.'"); }
void greet(AbstractRobot other) {
other.greet(this);
}}
TranslationRobot.Java
public class TranslationRobot extends AbstractRobot {
...
void greet(TranslationRobot other) {
talk("'Hello from a TranslationRobot to another.'"); }
void greet(CarrierRobot other) {
talk("'Hello from a CarrierRobot to a TranslationRobot.'"); }
void greet(AbstractRobot other) {
other.greet(this);
} }
DispatchWorld.Java
class DispatchWorld {
public static void main (String[] args) {
AbstractRobot c3po = new TranslationRobot();
AbstractRobot c4po = new TranslationRobot();
AbstractRobot c5po = new CarrierRobot();
AbstractRobot c6po = new CarrierRobot();
c3po.greet(c4po);
c5po.greet(c4po);
c4po.greet(c5po);
c5po.greet(c6po);
} }
This produces the output:
Standard Model says 'Hello from a TranslationRobot to another.'
Standard Model says 'Hello from a CarrierRobot to a TranslationRobot.'
Standard Model says 'Hello from a TranslationRobot to a CarrierRobot.'
Standard Model says 'Hello from a CarrierRobot to another.'
I think that the answer why this works and why there is no infinite recursion might be illustrated better if we refactor code a bit by removing all method overloading and putting explicit different names instead:
abstract class Robot
{
void talk(String msg)
{
System.out.println(msg);
}
}
abstract class AbstractRobot extends Robot
{
abstract void greet(AbstractRobot other);
abstract void greetFromTranslationRobot(TranslationRobot other);
abstract void greetFromCarrierRobot(CarrierRobot other);
}
class CarrierRobot extends AbstractRobot
{
void greetFromTranslationRobot(TranslationRobot other)
{
talk("'Hello from a TranslationRobot to a CarrierRobot.'");
}
void greetFromCarrierRobot(CarrierRobot other)
{
talk("'Hello from a CarrierRobot to another.'");
}
void greet(AbstractRobot other)
{
other.greetFromCarrierRobot(this);
}
}
public class TranslationRobot extends AbstractRobot
{
void greetFromTranslationRobot(TranslationRobot other)
{
talk("'Hello from a TranslationRobot to another.'");
}
void greetFromCarrierRobot(CarrierRobot other)
{
talk("'Hello from a CarrierRobot to a TranslationRobot.'");
}
void greet(AbstractRobot other)
{
other.greetFromTranslationRobot(this);
}
}
From the compiler's point of view methods void greet(AbstractRobot other), void greet(TranslationRobot other) and void greet(CarrierRobot other) are 3 obviously different methods which my renaming just highlights.
So a call like c3po.greet(c4po) is actually a call to TranslationRobot.greet which forwards it to other.greetFromTranslationRobot(this) which is TranslationRobot.greetFromTranslationRobot and which obviously should not result in any infinite recursion.

Subscription model with generics - implement multiple generic interfaces

So I tried to make a subscription model with generics.. it looked nice, but now I'm running into some issues.
Receiver
public interface Receiver<E> {
public void receive(E event);
}
Subscription registry
public class ClientRegistry<T> {
private Set<Receiver<T>> clients = new HashSet<Receiver<T>>();
public void subscribe(Receiver<T> client) {
clients.add(client);
}
public void unsubscribe(Receiver<T> client) {
clients.remove(client);
}
public void broadcast(T eventObject) {
for(Receiver<T> client: clients) {
client.receive(eventObject);
}
}
}
Sounds good so far, eh?
Now the problems come:
public class Screen implements Receiver<KeyEvent>, Receiver<MouseMoveEvent> {
#Override
public void receive(KeyEvent event)
{
// work
}
#Override
public void receive(MouseMoveEvent event)
{
// work
}
}
Now this is invalid syntax:
The interface Receiver cannot be implemented more than once
with different arguments: Receiver<MouseMoveEvent> and Receiver<KeyEvent>
How can I alter my system to keep it as generic as possible, but make it work?
Don't make the Screen class itself implement the two Receiver interfaces. Instead, use composition:
public class Screen {
private Receiver<KeyEvent> keyReceiver = new Receiver<KeyEvent>() {
...
};
private Receiver<MouseEvent> mouseReceiver = new Receiver<MouseEvent>() {
...
};
}
I would reverse the order, and use a Visitor Pattern:
import java.util.*;
interface Event{
void receive(Receiver receiver);
}
class KeyEvent implements Event{
#Override
public void receive(Receiver receiver){
receiver.receive(this);
}
}
class MouseEvent implements Event {
#Override
public void receive(Receiver receiver){
receiver.receive(this);
}
}
interface Receiver {
void receive(KeyEvent event);
void receive(MouseEvent event);
}
class ClientRegistry {
private Set<Receiver> clients = new HashSet<Receiver>();
public void subscribe(Receiver client) {
clients.add(client);
}
public void unsubscribe(Receiver client) {
clients.remove(client);
}
public void broadcast(Event eventObject) {
for(Receiver client: clients) {
eventObject.receive(client);
}
}
}
public class Screen implements Receiver {
public void receive(KeyEvent event) {
//work
System.out.println("Processing key event");
}
public void receive(MouseEvent event) {
//work
System.out.println("Processing mouse event");
}
public static void main(String[] args){
ClientRegistry registry = new ClientRegistry();
registry.subscribe(new Screen());
registry.broadcast(new MouseEvent());
}
}
There is not way to generify the Receiver interface, but it is indeed type safe and as you can see, I reverse the order, since now it is the event the one which chooses the receiver and not otherwise.

Categories

Resources