I'm working with students in my Java class on a simple Zork-like environment in which the player goes from location to location encountering items. The items should have dynamic behaviors, so that a book is readable until you burn it, or a duck can fly until it flies too long and tires out. And so on.
The students and I have grokked the basic Strategy pattern (I'm adapting from Head First Design Patterns, and leaving out boilerplate):
public class Duck {
String name;
Int health;
FlyBehavior flyBehavior;
public void performFly() {
flyBehavior.fly();
}
public void setFlyBehavior(FlyBehavior f) {
flyBehavior = f;
}
}
public interface FlyBehavior {
public void fly();
}
public class FlyGracefully implements FlyBehavior {
public void fly() {
System.out.println("I fly so gracefully!");
}
}
public class TooTiredToFly implements FlyBehavior {
public void fly() {
System.out.println("I'm too tired to fly.");
}
}
Sparing the details of the main method, this lets us switch different flying behaviors into our Duck. This is easy because it returns a void and prints to sysout.
But what if we need the behavior to interact with the state of the Duck? Let's say that:
When the duck becomes too tired to fly, its name changes to "Exhausted Duck." Other behaviors can change its name, too.
When the duck is attacked (gonna happen), its health goes down. When its health is too low, its flyBehavior switches out to the TooTiredToFly behavior.
But I'm assuming that dynamic behaviors, at least in this pattern, have no access to the state of the object they're in.
Is there a general strategy for creating dynamic behaviors that interact with the state of the object they're in? I would like to teach something comprehensible, so put yourself in the mind of intermediate-level high school programmers.
Based on my comment above, something along these lines...
// Creating an interface for flyable things e.g. Duck, Airplane, etc.
// You don't have to do this. You could just pass your Duck
// object instead and call its methods directly.
public interface Flyable {
void performFly();
}
public class Duck implements Flyable {
// All your Duck stuff as above in here.
}
public abstract class FlyBehavior {
private Flyable parent;
public FlyBehavior(Flyable parent) {
this.parent = parent;
}
public abstract void fly();
protected Flyable getParent() {
return this.parent;
}
}
public class FlyGracefullyBehavior extends FlyBehavior {
public FlyGracefullyBehavior(Flyable parent) {
super(parent);
}
#Override
public void fly() {
// Now you can get access to the original parent here.
Flyable parent = this.getParent();
}
}
public class TooTiredToFlyBehavior extends FlyBehavior {
public TooTiredToFlyBehavior(Flyable parent) {
super(parent);
}
#Override
public void fly() {
// Now you can get access to the original parent here.
Flyable parent = this.getParent();
}
}
Or, you could simply pass parent state in the fly method of your FlyBehavior classes i.e. behavior.fly(state); It's up to you :)
Here's a basic example of using the Strategy pattern as you have described. I'm trying to keep it as simple as possible so some best practices were ignored (e.g. declaring constants) so you can focus on the Strategy design and not be overwhelmed with information.
public interface Animal
{
public String getName();
public void attacked(int health);
}
public interface Bird extends Animal
{
public void fly();
}
public class Duck implements Bird
{
private Int health = 100;
private DuckBehavior state = new HealthyDuck();
public getName()
{
return state.getName();
}
public void fly()
{
state.fly();
}
public void attacked(int hitpoints)
{
health = health - hitpoints;
if (health < 50) {
state = new HurtDuck();
} else if (health < 0) {
state = new DeadDuck();
}
}
}
interface DuckBehavior
{
public getName();
public void fly();
}
public class HealthyDuck implements DuckBehavior
{
public getName()
{
return "Healthy Duck";
}
public void fly()
{
System.out.println("I fly so gracefully!");
}
}
public class HurtDuck implements DuckBehavior
{
public getName()
{
return "Hurt Duck";
}
public void fly()
{
System.out.println("I'm too tired to fly.");
}
}
public class DeadDuck implements DuckBehavior
{
public getName()
{
return "Dead Duck";
}
public void fly()
{
System.out.println("I'm too dead to fly.");
}
}
Lets add a new interface in the design as below
Flyable.java
public interface Flyable{
public void modifyTargetName(String newName);
}
Lets Modify the FlyBehavior.java and its implementation classes. Lets define a method public void setFlyableTarget( Flyable target ) in it.
FlyBehavior.java
public interface FlyBehavior {
public void fly();
public void setFlyableTarget( Flyable target );
}
FlyGracefully.java
public class FlyGracefully implements FlyBehavior {
public void fly() {
System.out.println("I fly so gracefully!");
}
public void setFlyableTarget( Flyable target ){
target.modifyTargetName("GraceFul Flyer");
}
}
TooTiredToFly.java
public class TooTiredToFly implements FlyBehavior {
public void fly() {
System.out.println("I'm too tired to fly.");
}
public void setFlyableTarget( Flyable target ){
target.modifyTargetName("TiredFlyer");
}
}
Duck.java let it implement Flyable.java
public class Duck implements Flyable{
String name;
Int health;
FlyBehavior flyBehavior;
public void modifyTargetName(String newName){
this.name = newName;
}
public void performFly() {
flyBehavior.fly();
}
public void setFlyBehavior(FlyBehavior f) {
flyBehavior = f;
f.setFlyableTarget(this);
}
}
The good thing here is we do not expose concrete implementation and hence code remains unit testable and good for adaptation to changes. It adheres to the DIP : Dependency Inversion Principle as well.
One general point I'd like to make: Don't modify internal behavior of an object, it's rude. I mean, there should not be a setFlyBehavior() method, that is an internal attribute of the Duck.
Also, think about who is responsible for what. Once a Duck is constructed, you can ask a Duck to fly, and you can make the Duck take Damage. How those things change the Duck is none of our business at that point.
On a more practical note, this is how that might look:
public interface Being {
boolean isDamaged();
}
public interface FlyingBehavior {
void fly();
}
public class GracefulFlyingBehavior implements FlyingBehavior {
...
}
public class TiredFlyingBehavior implements FlyingBehavior {
...
}
public class BirdFlyingBehavior implements FlyingBehavior {
private int tiredness;
...
public BirdFlyingBehavior(Being bird) {
...
}
#Override
public void fly() {
if (bird.isDamaged() || isTired()) {
tiredFlying.fly();
} else {
gracefulFlying.fly();
tiredness++; // Or whatever...
}
}
}
The point is, that the behavior itself should be responsible for deciding whether the flying can take place. It is after all the "strategy" for flying, so this logic needs to be there.
Then you can construct a duck something like this:
public Duck(String name, ... ) {
...
this.flyBehavior = new BirdFlyingBehavior(this);
}
or something similar. The point here is that once that strategy is set, it should stay internal to the Duck, there should be no way to modify that directly anymore.
Of course there might be additional features (you might want to move "tiredness" to the general "health" of a being), but the concepts should not change. Objects should hide their internal state, this requires "responsibilities" to be at the right place.
Related
I am way over thinking this: What I am trying to do is [hopefully not reinvent the wheel and] come up w/ a [Android] Java eventing mechanism that allows subclasses to pre-define an arbitrary set of "features" with getters and setters that fire individual callbacks.
I think I am fusioning some combination of Command, Visitor, Decorator, Facade and Observer patterns here, and confusing myself along the way.
I have been programming for well over 20 years, but I feel like a n00b on this fairly simple problem! :(
I have searched SO for the compiler error and read many of the results, but I still haven't found a solution that works for me.
(How to make a Java class that implements one interface with two generic types? seems to be the most relevant one that I have found, but I also want to generically get the values and fire events to callbacks when they are set).
First, let the below mostly valid code speak for itself...
interface IFeature
{
}
interface IFeatureCallbacks<T extends IFeature>
{
boolean onChanged(Feature<T> c);
}
public static class Feature<T extends IFeature>
{
private Set<IFeatureCallbacks<T>> listeners = new LinkedHashSet<>();
public void addListener(IFeatureCallbacks<T> listener)
{
listeners.add(listener);
}
public void removeListener(IFeatureCallbacks<T> listener)
{
listeners.remove(listener);
}
protected void onChanged()
{
for (IFeatureCallbacks<T> listener : listeners)
{
listener.onChanged(this);
}
}
}
//
interface IFeatureA
extends IFeature
{
int getA();
}
interface IFeatureACallbacks
extends IFeatureCallbacks<IFeatureA>
{
}
public static class FeatureA
extends Feature<IFeatureA>
implements IFeatureA
{
private int a;
public void setA(int value)
{
a = value;
onChanged();
}
#Override
public int getA()
{
return a;
}
}
//
interface IFeatureB
extends IFeature
{
boolean getB();
}
interface IFeatureBCallbacks
extends IFeatureCallbacks<IFeatureB>
{
}
public static class FeatureB
extends Feature<IFeatureB>
implements IFeatureB
{
private boolean b;
public void setB(boolean value)
{
b = value;
onChanged();
}
#Override
public boolean getB()
{
return b;
}
}
//
interface IDeviceWithFeatureA
extends IFeatureA
{
}
interface IDeviceWithFeatureACallbacks
extends IFeatureACallbacks
{
}
public static class DeviceWithFeatureA
extends Feature<IDeviceWithFeatureA>
implements IDeviceWithFeatureA
{
FeatureA a = new FeatureA();
public void addListener(IDeviceWithFeatureACallbacks listener)
{
a.addListener(listener);
}
public void setA(int value)
{
a.setA(value);
}
#Override
public int getA()
{
return a.getA();
}
}
//
interface IDeviceWithFeatureB
extends IFeatureB
{
}
interface IDeviceWithFeatureBCallbacks
extends IFeatureBCallbacks
{
}
public static class DeviceWithFeatureAB
extends Feature<IDeviceWithFeatureB>
implements IDeviceWithFeatureB
{
FeatureB b = new FeatureB();
public void addListener(IDeviceWithFeatureBCallbacks listener)
{
b.addListener(listener);
}
public void setB(boolean value)
{
b.setB(value);
}
#Override
public boolean getB()
{
return b.getB();
}
}
The above code seems to work fine, albeit something about it smells a bit off.
The problem is when I try to do this:
interface IDeviceWithFeatureAAndFeatureB
extends IFeatureA, IFeatureB
{
}
/*
Compiler error:
'IFeatureCallbacks' cannot be inherited with different type arguments 'IFeatureA' and 'IFeatureB'
*/
interface IDeviceWithFeatureAAndFeatureBCallbacks
extends IFeatureACallbacks, IFeatureBCallbacks
{
}
public static class DeviceWithFeatureAB
extends Feature<IDeviceWithFeatureAAndFeatureB>
implements IDeviceWithFeatureAAndFeatureB
{
FeatureA a = new FeatureA();
FeatureB b = new FeatureB();
public void addListener(IDeviceWithFeatureAAndFeatureBCallbacks listener)
{
a.addListener(listener);
b.addListener(listener);
}
public void setA(int value)
{
a.setA(value);
}
#Override
public int getA()
{
return a.getA();
}
public void setB(boolean value)
{
b.setB(value);
}
#Override
public boolean getB()
{
return b.getB();
}
}
I am less interested in trying to figure out how to make what I am trying to do compilable, and I am more interested in what about my abuse of a pattern is way off base so that I can re-write it to be both simpler and compile.
You are abusing the basic "pattern" of OOP -- inheritance. The adage is that "favor composition over inheritance". Think in terms of "contains", instead of "is-a".
Take Zoo for example. A zoo is just a bunch of animals, right? So naturally, we may want to declare Zoo as subtype of Set<Animal>. Perhaps even have class Zoo extends HashSet<Animal>.
However, that is likely a wrong design. A zoo is actually a lot of things. It contains a set of animals, sure; but it also contains a set of people (as workers, not exhibits (although...) ). So it's better to
class Zoo
Set<Animal> animals(){ ... }
Set<Person> workers(){ ... }
Anywhere we need to treat a zoo as a set of animals, just use zoo.animals(); think of it as a type cast, or projection. We don't need inheritance here.
In your design, you have too many types; what's worse, too many type relationships. It seems that you simply need one generic class that reads/writes value of T, and contains listeners of T
class Feature<T>
T value;
// getter
// setter
Set<ChangeListener<T>> listeners;
interface ChangeListener<T>
void onChange(T oldValue, T newValue)
A device contains a bunch of features
class SomeDevice
Feature<Integer> featureA = new Feature<>();
Feature<Boolean> featureB = new Feature<>();
That's it. You can operate on feature A of the device by operating on itsfeatureA.
In a project, I have a service and a class using that service. In this example case a repair service that will be used by vehicles. A repair service can only repair a certain type of vehicle: The garage can only repair cars. I need a method in the vehicle to repair it with an applicable service, repairUsingService(..).
My goal is to have a clean Vehicle base class and clean RepairService implementations. I have tried two ways of designing the repair method of the repair service:
repair(Vehicle<T> vehicle): This is ugly because implementations would need to do repair(Vehicle<Car> car) but it is obvious that a car is a vehicle.
repairSimple(T vehicle): Is nice with that but cannot be called from the Vehicle class without an ugly cast.
Is there a way to avoid casting but still only use the generic parameter type T (like in repairSimple(T))?
public class Vehicle<T extends Vehicle<T>> {
public void repairUsingService(RepairService<T> obj) {
obj.repair(this);
obj.repairSimple((T) this);
}
}
public class Car extends Vehicle<Car> {
}
public interface RepairService<T extends Vehicle<T>> {
void repair(Vehicle<T> vehicle);
void repairSimple(T vehicle);
}
public class Garage implements RepairService<Car> {
#Override
public void repair(Vehicle<Car> car) {
System.out.println("Car repaired.");
}
#Override
public void repairSimple(Car car) {
System.out.println("Car repaired.");
}
}
Could you use this implementation? This way both the vehicle knows, what repair service can repair it, and the service knows, what vehicles it can repair.
public interface RepairService<T extends Vehicle<?>> {
public void repair(T vehicle);
}
public interface Vehicle<T extends RepairService<?>> {
public void repairUsingService(T service);
}
public class Car implements Vehicle<Garage> {
#Override
public void repairUsingService(Garage service) {
}
}
public class Garage implements RepairService<Car>{
#Override
public void repair(Car vehicle) {
}
}
public class AuthorizedGarage extends Garage {
}
public class Train implements Vehicle<TrainDepot> {
#Override
public void repairUsingService(TrainDepot service) {
}
}
public class TrainDepot implements RepairService<Train> {
#Override
public void repair(Train vehicle) {
}
}
public class Test {
public static void main(String[] args) {
// this works:
new Car().repairUsingService(new Garage());
new Train().repairUsingService(new TrainDepot());
// and this works
new Garage().repair(new Car());
new TrainDepot().repair(new Train());
// but this does not (which is ok)
//new Garage().repair(new Train());
//new Car().repairUsingService(new TrainDepot());
// this also works
List<Car> cars = new ArrayList<>();
cars.add(new Car());
cars.get(0).repairUsingService(new Garage());
// this also works, if you have an expensive car ;)
new Car().repairUsingService(new AuthorizedGarage());
}
}
You could even have a base class for all your repair services to avoid code repetition:
public abstract class BaseRepairService<T extends Vehicle<?>> implements
RepairService<T> {
#Override
public void repair(T vehicle) {
}
}
Then your Garage would extend a BaseRepairService with a Car type parameter.
One way is to ask the subclass for itself:
abstract class Vehicle<T extends Vehicle<T>> {
public void repairUsingService(RepairService<T> obj) {
obj.repair(this);
obj.repairSimple(getThis());
}
abstract T getThis();
}
class Car extends Vehicle<Car> {
#Override
Car getThis(){
return this;
}
}
Let me present two reasonable alternatives.
The first is a variation of Gafter's Gadget:
public abstract class Vehicle<V extends Vehicle<V>> {
private boolean validate() {
Class<?> cls = getClass();
for(Class<?> sup;
(sup = cls.getSuperclass()) != Vehicle.class;
cls = sup
);
Type sup = cls.getGenericSuperclass();
if(!(sup instanceof ParameterizedType))
return false;
Type arg = ((ParameterizedType)sup).getActualTypeArguments()[0];
if(!(arg instanceof Class<?>))
return false;
return ((Class<?>)arg).isInstance(this);
}
protected Vehicle() {
assert validate() : "somebody messed up";
}
}
Since Vehicle is always parameterized by a subclass, it's OK to use this idiom. During development you run with assertions on and the constructor will throw an error if somebody extends the class incorrectly.
Now the unchecked cast is always safe.
The second is that RepairService no longer carries a type parameter. Instead, you keep a listing of Class<? extends Vehicle> the RepairService can repair.
public interface RepairService {
boolean canRepair(Vehicle v);
// if v can't be repaired, perhaps repair
// throws an exception or returns boolean instead of void
void repair(Vehicle v);
}
public class ServiceStation implements RepairService {
private final List<Class<? extends Vehicle>> types;
public ServiceStation(Class<? extends Vehicle>... types) {
this.types = Arrays.asList(types);
}
#Override
public boolean canRepair(Vehicle v) {
for(Class<? extends Vehicle> c : types) {
if(c.isInstance(v))
return true;
}
return false;
}
#Override
public void repair(Vehicle v) {
if(!canRepair(v))
throw new IllegalArgumentException();
// impl
}
}
At least for the Vehicle/RepairStation analogy this is probably much more usable than trying to force generics in to the design. Vehicle probably doesn't need a type parameter either anymore.
Maybe your actual program is different but you should always consider whether straight program logic solves the problem before introducing a parametric design. Trying to force generics to work in a situation where they are a suboptimal solution gets very awkward.
I'm trying to check if class A that is extending class B is instance of certain interface.
Basically here is my setup:
public class House
{
(variables)
public House(variables) {...}
}
public class Kitchen extends House implements IFurniture
{
(variables)
public Kitchen(variables)
{
super(variables);
}
}
public class Bathroom extends House implements IWalls
and so on...
And I have a method where I'm getting a casted, House version of Kitchen and Bathroom.
I basically want to do this:
public boolean hasFurniture(House house)
{
if (house instanceof IFurniture){return true;}
}
Do I need to use house.getClass().getInterfaces() and would that even work considering that the argument has been casted?
The problem is that I'm writing a mod for a game and I can't edit games classes. Only only Kitchen, Bathroom and hasFurniture can be edited in this case.
Also ignore my class names, they are just example names so that you don't confuse Classes accidentally.
You're wasting the benefits of polymorphism. You don't want to use an interface with instanceof to check if an object has a property. implements and extends mean IS-A, not HAS-A. You clearly want the latter. Do it like this instead:
public interface IFurniture {
public boolean hasFurniture();
}
public class House implements IFurniture
{
(variables)
public House(variables) {...}
#Override
public boolean hasFurniture() {
return false;
}
}
public class Kitchen extends House
{
(variables)
public Kitchen(variables)
{
super(variables);
}
#Override
public boolean hasFurniture() {
return true;
}
}
EDIT: Also, Eran is right to point out that this hierarchy doesn't make a huge amount of sense in the first place -- but that's a larger issue.
Let's work with a more understandable class hierarchy.
You're thinking about the instanceof issue like this:
public class Person{
public void die(){
System.out.println(this + " died");
}
public void pushOffCliff(){
if(this instanceof Flyable)
Flyable f = (Flyable)this;
f.fly();
else
die();
}
}
public interface Flyable{
public void fly();
}
public class Superhero extends Person implements Flyable{
public void fly(){
System.out.println("Up, up, and away!");
}
}
When it makes much more sense to use the class extension and overriding system like Patrick does in his answer, like below. People (that are truly just people and not superheroes) don't fly. When pushed off a cliff, they should die. So the person class shouldn't deal with the "what if I'm not truly a person, I'm actually an ...." possibility; let the sub classes deal with that.
public class Person{
public void die(){
System.out.println(this + " died");
}
public void pushOffCliff(){
die();
}
}
public interface Flyable{
public void fly();
}
public class Superhero extends Person implements Flyable{
public void fly(){
System.out.println("Up, up, and away!");
}
#Override
public void pushOffCliff(){
fly();
}
}
I just solved it, thanks to Eran.
My problem was that I was casting a wrong element.
In this case I was casting ItemStack (Item with additional data) instead of Item.
By adding just .getItem() I have hopefully solved the problem.
Thank you for helping, have a nice day!
Consider the simple example below of implementing a method in an Enum. One problem with this method is that, when you have a lot of enum instances, you visually can no longer see them all at once, as a list. That is, if we had many toys, I would like to see "DOLL, SOLDIER, TEDDYBEAR, TRAIN, ETC", together, in one long list, and then after that list I could implement any needed methods, e.g. methods that are abstract in the enum itself.
Is there any way to do this? Or do you have to implement the methods when you declare the individual enum instances, as in the example below?
public enum Toy {
DOLL() {
#Override public void execute() {
System.out.println("I'm a doll.");
}
},
SOLDIER() {
#Override public void execute() {
System.out.println("I'm a soldier.");
}
};
//abstract method
public abstract void execute();
}
One way that comes to mind is to leave the implementation of the abstract methods to separate implementation classes, something like:
interface ToyBehaviour {
void execute();
}
public enum Toy {
DOLL(new DollBehaviour()),
SOLDIER(new SoldierBehaviour());
private final ToyBehaviour behaviour;
Toy(ToyBehaviour impl) {
behaviour = impl;
}
public void execute() {
behaviour.execute();
}
}
class DollBehaviour implements ToyBehaviour {
public void execute() {
System.out.println("I'm a doll.");
}
}
This setup would allow you to create behaviour classes in separate files in the case that your implementation has enough complexity to warrant separation.
In the case that the implementation is simple enough to include it into the one enum class, you can put the interface and behaviour classes as children of the enum class:
public enum Toy {
// enum values
DOLL(new DollBehaviour()),
SOLDIER(new SoldierBehaviour());
private final ToyBehaviour behaviour;
Toy(ToyBehaviour impl) {
behaviour = impl;
}
public void execute() {
behaviour.execute();
}
// behaviour interface
interface ToyBehaviour {
void execute();
}
// behaviour implementation (sub)classes
static class DollBehaviour implements ToyBehaviour {
public void execute() {
System.out.println("I'm a doll.");
}
}
// etc ...
}
I would probably opt for the first implementation myself, unless the hierarchy of implementation classes is very trivial.
If you want more compact enum declarations, the only ways I can think of to do it are :
if you can construct your methods out of initializer variables:
public enum Toy {
DOLL("doll"),SOLDIER("soldier");
private Toy(String name){ this.name=name;}
public void execute(){ System.out.println("I'm a "+name );}
}
or, slightly more complicated, kind of the same with functions, if the behavior is more complex -
abstract class SomeToyMethod {
abstract void execute();
public SomeToyMethod DOLL_METHOD = new SomeToyMethod(){
public void execute(){ System.out.println("I'm a doll");})
public SomeToyMethod SOLDIER_METHOD = new SomeToyMethod(){
public void execute(){ System.out.println("I'm a soldier");})
public enum Toy {
DOLL(SomeToyMethod,DOLL_METHOD),SOLDIER(SomeToyMethod.SOLDIER_METHOD);
private Toy(SomeToyMethod method){ this.method=method;}
public void execute(){ method.execute();}
}
You could try something like:
public enum Toy {
DOLL,
SOLDIER,
ANOTHER_TOY;
public static void execute(Toy toy) {
switch(toy) {
case DOLL:
System.out.println("I'm a doll.");
break;
case SOLDIER:
System.out.println("I'm a soldier.");
break;
case ANOTHER_TOY:
System.out.println("I'm another toy.");
break;
}
}
}
Not very pretty but it keeps your enum declarations together.
I am currently working on a project where I am attempting to hide as much detail about a hierarchy I have created as possible. I want to do this to minimize the amount of information the user needs to know about objects (and to control what they can do to the state of the object). In addition, I'm using the pattern to limit what kinds of objects the application can make, and limit it to creation from the factory.
The main issue I am having, however, is that there are a few different kinds of interfaces I would like to expose. Each interface is has additional functionality that I don't believe should be shared, and I would like to keep these interfaces separated. Finally, I don't know what new interfaces may come in the future, but I'd like to try and be ready for them.
Weapon:
public interface Weapon extends GameObject {
Number attack();
boolean addWeaponAttribute(WeaponAttribute attribute);
}
Firearm:
public interface Firearm extends Weapon {
void reload(Number rounds);
}
My question is what would be the best way to have the factory produce objects with different interfaces? Here's what I am thinking "the best would be":
The most clear to the user (it's obvious what they're asking for and what they're getting back)
The best for future expansion (I am uncertain what new interfaces I will be adding to this system).
Here's what I have been thinking so far:
Create properly named methods for each interface
public static Firearm getFirearm(String firearmName) {
...
}
public static Weapon getWeapon(String weaponName) {
...
}
Do the above, but produce the factories in separately named classes
public class WeaponFactory {
public static Weapon getWeapon(String weaponName) {
...
}
}
public class FirearmFactory {
public static Firearm getFirearm(String firearmName) {
...
}
}
Something completely different
I'm open to suggestions, and changes. This is a flexible project, so I can change as much as I want to (in terms of this portion of the project) to make a better result.
Also - As a side note, I was uncertain if this question was too open-ended or not for SO. If I made a mistake posting here, let me know and I'll move my question elsewhere.
What I can suggest is to make the interfaces as concise as possible and move other unrelated methods elsewhere. you might consider doing this for example:
public interface Weapon extends GameObject {
Number attack();
}
public interface Modifiable extends GameObject {
boolean addWeaponAttribute(WeaponAttribute attribute);
}
public class ActualWeapon implements Weapon, Modifiable {
...
}
Then you can create different factories to generate your concrete objects, as you already mentioned:
public class WeaponFactory {
public static Weapon getWeapon(String weaponName) {
...
}
}
or
public class GenericFactory<T extends GameObject> {
public T createGameObject(Object... properties) {
...
}
}
public class WeaponFactory extends GenericFactory<ActualWeapon> {
public ActualWeapon createGameObject(Object... properties) {
...
}
}
I think you can't add static methods to interfaces. I wouldn't recommend it if you even could.
maybe just use the factory method design pattern like
interface GameObject {}
class WeaponAttribute {}
interface Weapon extends GameObject {
Number attack();
boolean addWeaponAttribute(WeaponAttribute attribute);
}
interface Firearm extends Weapon {
void reload(Number rounds);
}
class WeaponBaseClass implements Weapon {
WeaponBaseClass(WeaponName weaponName) {
this.weaponName=weaponName;
}
#Override public Number attack() {
return null;
}
#Override public boolean addWeaponAttribute(WeaponAttribute attribute) {
return false;
}
public String toString() {
return weaponName.toString();
}
final WeaponName weaponName;
}
class FirearmBaseClass extends WeaponBaseClass implements Firearm {
public FirearmBaseClass(WeaponName weaponName) {
super(weaponName);
}
#Override public void reload(Number rounds) {}
}
enum WeaponName {
knife, sword, colt45, glock19, glock19WithLaser;
}
class WeaponCreator {
Weapon create(WeaponName weaponName) {
switch (weaponName) {
case knife:
case sword:
return new WeaponBaseClass(weaponName);
case colt45:
case glock19:
return new FirearmBaseClass(weaponName);
default:
return new WeaponBaseClass(weaponName);
}
}
}
class FancyWeaponCreator extends WeaponCreator {
Weapon create(WeaponName weaponName) {
Weapon weapon = null;
switch (weaponName) {
case glock19WithLaser:
weapon = super.create(WeaponName.glock19);
// whatever it needs
return weapon;
default:
return new WeaponBaseClass(weaponName);
}
}
}
public class Main {
public static void main(String[] args) {
System.out.println(new WeaponCreator().create(WeaponName.knife));
System.out.println(new WeaponCreator().create(WeaponName.colt45));
System.out.println(new FancyWeaponCreator().create(WeaponName.glock19WithLaser));
}
}
What about a factory of factories? Each factory would implement ifactory. Ifacorty would require a method Instantiate(string type) and return your subclassed weapon instance.
Using generics, you might only need one factory method like:
public <T> T getObject(java.lang.Class<T> responseType, String name)
Then the user would call:
Weapon weapon = factory.getObject(Weapon.class, "my weapon");