Trying to get my head around the factory design pattern

Hey again, so yeah i have been messing about trying to figure out the practicalities of the factory design pattern in java.
before i show you my code let me try to explain what i am trying to do. I am trying to create some functionality that will allow you to create any type of entity (lets say you wanted to build infantry as opposed to tanks) you wish on runtime and also allow me to extend on what types of entities i want to allow be created without having to mess around. So anyways here is what i have.


//this is actually the factory for creating entities.
package com.niroshido.gameObjects;

public class EntityFactory {
	
	public Entity create(String name){
		switch(name.toLowerCase()){
		case "aircraft": Entity air = new Aircraft();
		return air;
		case "tank": Entity tank = new Tank();
		return tank;
		default: return null;
		}		
	}
}


//yup this interface doesn't do anything, i had spent a while trying to figure out
//what if anything should be inside this interface, but i draw a blank.
package com.niroshido.gameObjects;

public interface Entity {
	
}



//this is a super class that most entites would inherit from, the exception being things that can't move/attack like //buildings
package com.niroshido.gameObjects;

public class Units implements Entity{

	private int healthPoints;
	private int attackDamage;
	private int speed;
	private int rotationSpeed;

	public void move(){
		
	}
	
	public void drawUnit(){
		
	}
	
	public void attack(Entity e, Entity target){
		
	}
	
	public int getHealthPoints() {
		return healthPoints;
	}
	
	public void setHealthPoints(int healthPoints) {
		this.healthPoints = healthPoints;
	}
	
	public int getAttackDamage() {
		return attackDamage;
	}
	
	public void setAttackDamage(int attackDamage) {
		this.attackDamage = attackDamage;
	}
	
	public int getSpeed() {
		return speed;
	}
	
	public void setSpeed(int speed) {
		this.speed = speed;
	}
	
	public int getRotationSpeed() {
		return rotationSpeed;
	}
	
	public void setRotationSpeed(int rotationSpeed) {
		this.rotationSpeed = rotationSpeed;
	}	
}


//this is rather obvious, its a subclass, a specific type of unit.
package com.niroshido.gameObjects;

public class Tank extends Units{
	
	public Tank(){
		System.out.println("tank");
		this.setHealthPoints(200);
		System.out.println(this.getHealthPoints());
	}
	
	public void move(){
		
	}
}

in my mind this is how i see my code as is
factory <- Creates- Entity <-implements- Units<-extends- Tank

now my main issue really comes down to, moving, drawing, attacking etc. In my factory class i decided to try and see if i could call a method from Tank, i can’t it wont allow me, i assume that this is actually logical and expected after all the factory design pattern is supposed to abstract the creation process and simply stop people from screwing around with the actual sub class of Units directly, am i right with this?. If this is the case what would the point of me having move or any of those methods in Units if i can’t access them as a result (at this point i clearly need to guidance), should i not have those methods there and simply create a different class for processing orders (attack, move, defend) that take a type of Entity as a parameter, I am sure there is a lot of people here who could understand what i am trying to achieve, possibly.

to describe this is a nut shell, i obsess about good code design, if i feel that if its not designed to the point it shines like a lighthouse at night i have failed miserably.

The factory pattern is for initialising classes with lots of variables to be set, but where some may be fine just left as the defaults.

The point is you create a factory, and then set the options you want to change from the defaults, and then call a finish function to get the final object.


SomeFactory factory = new SomeFactory();

factory.setSomeInt(5);
factory.setSomeString("This statement is false");

SomeObject object = factory.getResult();


Where factory may have lots more functions available than the ones you called.

Once the object has been fully initialised, you should not be using the factory anymore.

Edit: Disregard the above. I mixed up the Factory and Builder patterns.

More on design patterns:

Never do something because the code looks nice.
Do something because it’s the most efficient way of doing it.
Your end-user will care more about you getting the project done faster than being told “the code looks nicer”.
Fortunately, efficient coding usually looks nice.

note: im no guru and this is probably not my place to say

but as for your entity system

the whole point of an entity system is to be able to dynamically control more then one character i.e. tank, soldier, plane so you dont have to have separate interaction functions for each character (polymorphic)

just wanted to say that after seeing your empty entity interface (not sure if was example orrr…)

also in this case your entity interface is pointless and unit should be renamed to entity

as for your main question

id just have a controller class storing all your entities with the same concept of the “entity” system itself

What about non-unit entities?

i was only speaking in terms of this case

Nope, thats the Builder-Pattern :wink:

Yes it is. I mixed them up. :cranky:

hi everyone, thanks for the replies, i think i need to go into more detail about what i am trying to achieve.
I like RPG’s and RTS games, my idea was to eventually piece together an RTS. my entity based system was designed to include stuff that typically cannot be interacted with by the player as well as those that can, it is supposed to encompass all types of object, i wanted to keep it abstract enough so that i could simply just add a new class to define a new type of entity when i come up with an idea.

i chose the factory pattern because my understanding is the factory pattern abstracts what is being instantiated. An entity can be anything within the game world, it can be a treasure chest or it could be a soldier, it may be passable it may not.

I’ll start off by commenting on your code, and explaining its flaws.


public class EntityFactory {
   
   public Entity create(String name){
      switch(name.toLowerCase()){
      case "aircraft": Entity air = new Aircraft();
      return air;
      case "tank": Entity tank = new Tank();
      return tank;
      default: return null;
      }      
   }
}

This has a couple of issues:

  • Returns null if the wrong string is passed in, i.e it’s not type-safe.
  • Requires an instance of the class to create an entity.

Fixing those issues would result in this:


public class EntityFactory {

	public enum EntityType {
		AIRCRAFT, TANK;
	}
   
	public static Entity create(EntityType type) {
		switch(type) {
		case AIRCRAFT: 
			return new Aircraft();
			break;
		case TANK:
			return new Tank();
			break;
		}      
	}
}

This ensures type safety meaning that all errors are picked up at compile time, however it doesn’t go far enough. You have both an enum and a class, however the class only has one static method in it. You could simply move the static method to the enum, which would result in this:


public enum EntityType {
	AIRCRAFT, TANK;
   
	public static Entity create(EntityType type) {
		switch(type) {
		case AIRCRAFT: 
			return new Aircraft();
			break;
		case TANK:
			return new Tank();
			break;
		}      
	}
}

Another way to do it would to be to get rid of the static method altogether and replace it with an abstract method in the enum. This would look like:


public enum EntityType {
	AIRCRAFT {
		@Override
		public Entity create() {
			return new Aircraft();
		}
	},
	TANK {
		@Override
		public Entity create() {
			return new Tank();
		}
	};
   
	public abstract Entity create();
}

And you could create an entity by simply calling [icode]Entity aircraft = EntityType.AIRCRAFT.create()[/icode]. However all of this seems unnecessary, which it is.

Your main issue is that you’re not using Unit as the base class. Think about it this way, if entity is a unit, why do you inherit the behaviours and states of an entity as a unit? Instead, you should be inheriting the behaviours and states of a unit as an entity. If you had another class, for example Building, then inheriting the behaviours and states for an entity and for a building would mean that every unit would be both a building and an entity. Inheriting the behaviours and states for a unit as a building and as an entity would mean that a building is a unit and that an entity is a unit. Everything has an is a relationship.

  • Entity is a unit
  • Building is a unit
  • Aircraft is an entity
  • Tank is an entity
  • House is a building
  • Tower is a building

This means that Aircraft should inherit the behaviours and states of Entity and that Entity should inherit the behaviours and states of Unit. Similarly, Tower should inherit the behaviours and states of Building and Building should inherit the behaviours and states of Unit. Forget about using interfaces; only use an interface for an behaves like a relationship. Instead, use abstract classes. Interfaces allow you to inherit the types of behaviours of an object, and to specify how the object acts out those behaviours. Abstract classes allow you to inherit an objects states, an objects pre-specified behaviours and allows you to abstract certain behaviours in the same way as an interface.

So if every unit has health, you would create an abstract unit class and specify health as a state.


public abstract class Unit {

	protected int health;

	protected Unit(int health) {
		this.health = health;
	}
 
	// note that it's package-private, only allows other units to set health
	void applyDamage(int damage) {
		health -= damage;
		if (health <= 0) {
			destruct();
		}
	}

	public int getHealth() {
		return health;
	}

	abstract void destruct(); // each unit might destruct in a different way

}

If every Entity is a unit and can attack other units, however the way in which each unit attacks other units is different, you would create an abstract Entity class that abstracts how the entity attacks another unit.


public abstract class Entity extends Unit {

	protected int speed;
	protected int damage;

	protected Entity(int attackSpeed, int attackDamage, int health) {
		super(health);
		this.speed = attackSpeed;
		this.damage = attackDamage;
	}

	public abstract void attack(Unit unit);

	public abstract void destruct();

}

And for each entity you would abstract the attack method, e.g:


public class Aircraft extends Unit {

	public Aircraft(int attackSpeed, int attackDamage, int health) {
		super(attackSpeed, attackDamage, health);
	}

	public void attack(Unit unit) {
		unit.applyDamage(damage); // apply damage at a certain rate, do whatever... you can do some fancy stuff
	}

	public void destruct() {
		// do some animation, maybe fall to ground and explode? apply damage from this for example?
	}

}

So yeah, designing it in this way allows you to specify the behaviours you want to inherit and how you want to inherit them. To create an Aircraft for example, you can just do [icode]Unit aircraft = new Aircraft(20, 2, 100)[/icode]. It’s much better than your old approach. Oh, and just to note that if every entity for example attacked other units in the same way, then you could just specify the behaviour of attacking other units in the entity class and you wouldn’t need to abstract it.

Thats a very detailed response Troubleshoots, thank you. I will have to re-read the reply so i can fully absorb what you are explaining but i certainly appreciate it

Hmm nice read. Bookmarked :stuck_out_tongue:
Edit: I guess you could put those abstract methods into an interface to further clean up your base class for example.

Also this is a good read to learn about the difference between abstract classes and interfaces
http://obviam.net/index.php/design-in-game-entities-object-composition-strategies-part-1/

Ive never written a factory class in my life, but the internet tells me that you use a factory pattern when you want to delegate the business of creating something form the code that uses it.

Like - i want to use an iPad, but I don’t want to have to build one. I don’t know how to build one - so I delegate that to Apple.

This is a separate issue to what you are concerned with, which is ( I believe) that all your entities have a common interface?