How to Use Object Pool Pattern

Use: When creating an object is expensive like reading from a file or accessing a database. Object Pool is best when you are repeatedly creating and destroying many identical objects. If you are only using an object once in your code, object pool will not save you anything. It will add more unnecessary complexity and memory overhead.

Best Practices are to create just enough objects. Some implementations allow the pool to grow if an object isn’t available, however you could waste memory if there is not a consistent amount of objects needed by your program. If you do want to allow your pool to grow, add a max size to prevent memory leaks. If you are using multi-threading and your pool is at max size when a request is made it can wait for one to become available. However with threading, you might want your object pool to be a singleton for each type of object you want to build a pool.

Like Factory Pattern the Object Pool creates the objects for you. An object Pool can only consist of similar objects of the same type. The important thing is that they need to be interchangeable.

Store and Array of objects.

Keep a list of objects not in use.

How to Create Object Pool Pattern

An object pool is an object that stores objects in a data structure to create object permanence. Inside there is a mechanism to identify which objects are not currently in use. There should be a public method to request an object that will return an object that is available for reuse. A second public method should allow an object to be returned, thus adding it back to the list of unused objects and resetting the defaults on the object.

Any object can be stored in an object pool given reasonable default values that can be reset with less work than it would take to just make a new object.

The Third object used in this pattern is the requesting object. This is a controller that uses whichever objects are stored in your pool. It needs to make sure it returns the object when it is finished or this pattern doesn’t work. It also needs to handle the case of an object no being available for use when requested.

Code Samples

Object to be Pooled
/**
* Jami Schwarzwalder
* Enemy.java
*
*/

package edu.greenriver.it;

import java.awt.geom.Point2D;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;

import javax.imageio.ImageIO;

public class Enemy {

private Point2D position;
private BufferedImage appearance;

public Enemy(Point2D position, String apperanceLocation) {
         this.position = position;
         try {
              this.appearance = ImageIO.read(new File(apperanceLocation));
         } catch (IOException e) {
              System.out.println(e);
     }
    
}

public void start() {

    //begin animation
    //move toward hero
}

public void destroy() {

    //add points to score
    //destroy child objects

}

public void SetPosition(Point2D position) {
    this.position = position;
}

public Point2D GetPosition(){
    return position;
}

public BufferedImage GetAppearance(){
    return appearance;
    }

}

Object Pool Interface
/**
* Jami Schwarzwalder
* IObjectPool.java
*
*/

package edu.greenriver.it;

public interface IObjectPool<T> {

    public T getObject ();

    public void returnObject(T object);

}
Object Pool for Specific Object
/**
* Jami Schwarzwalder
* EnemyPool.java
*
*/

package edu.greenriver.it;

import java.awt.geom.Point2D;
import java.util.LinkedList;

public class EnemyPool implements IObjectPool<Enemy> {
    // starting values for Enemy Object
    private Point2D startingPosition;
    private String appearanceLocation;

    // Option 1 is to generate objects when initialized
    private int poolSize = 15;

    // Option 2 is to generate objects when requested and none are available
    private int maxPoolSize = 50;

    // create list to store objects
    private LinkedList<Enemy> waitingObjectPool = new LinkedList<Enemy>();
    private Enemy[] enemyPool = new Enemy[maxPoolSize];

    public EnemyPool(Point2D startingPosition, String appearanceLocation) {
        this.startingPosition = startingPosition;
        this.appearanceLocation = appearanceLocation;

        for (int i = 0; i < poolSize; i++) {
            createEnemy(startingPosition, appearanceLocation, i);
        }
    }
    private void createEnemy(Point2D startingPosition, String appearanceLocation, int i) {
         enemyPool[i] = new Enemy(startingPosition, appearanceLocation);
         waitingObjectPool.add(enemyPool[i]);
    }

    @Override
    public Enemy getObject() {
         if (waitingObjectPool.isEmpty()) {
              if (poolSize < maxPoolSize) {
                createEnemy(startingPosition, appearanceLocation, poolSize);
                poolSize += 1;
             } else {
                    return null;
             }
         }
         return waitingObjectPool.removeFirst();
    }

    @Override
    public void returnObject(Enemy object) {
         object.SetPosition(startingPosition);
         waitingObjectPool.add(object);

    }

}
Controller Object
/**
* Jami Schwarzwalder
* GameManager.java
*
*/

package edu.greenriver.it;

import java.awt.geom.Point2D;

public class GameManager {
    public static void main(String[] args) {
        String goombaImage = "Goomba.png";

        Enemy[] enemies = new Enemy[10];

        //Create a line of 10 goombas at ground level
        for (int i = 0; i < enemies.length; i++){
            enemies[i] = new Enemy(new Point2D.Float(i * 10, 10), goombaImage);
        }

        //Hero engages with enemy and kills them all

        for (int i = 0; i < enemies.length; i++){
            enemies[i] = null;
        }

        //Hero continues in game and encounters more enemies
        //This time we have decided we want to reuse enemies
        //so we will use an object pool of enemies

        IObjectPool<Enemy> enemyPool = new EnemyPool(new Point2D.Float(-10, -10), goombaImage);
        for (int i = 0; i < enemies.length; ++i){
            enemies[i] = enemyPool.getObject();
            enemies[i].SetPosition(new Point2D.Float(i *10, 10));
        }

        //Hero engages with the first enemy and destroys it
        //enemy will not be destroyed but will be moved offscreen and made available for reuse later

        enemyPool.returnObject(enemies[0]);

        //There was one more enemy lurking offscreen
        //Object pool will reuse the destroyed enemy so that the image doesn't need to be reloaded

        Enemy supriseEnemy = enemyPool.getObject();
        supriseEnemy.SetPosition(new Point2D.Float(100, 10));
        
    }
}

Resources Used

Baby Luigi. "Mario Party 7 Image." MarioWiki. Nintendo, 24 Sept. 2012. Web. 02 Dec. 2016.

Davis, Thomas E. "Build Your Own ObjectPool in Java to Boost App Speed." JavaWorld. JavaWorld, 1 June 1998. Web. 29 Nov. 2016.

Geig, Mike. "Object Pooling." Unity Learning Pages. Unity 3D, 7 Apr. 2014. Web. 29 Nov. 2016.

Kumar, Abhishek. "Creating Object Pool in Java." DZone. Performance Zone, 14 Apr. 2014. Web. 29 Nov. 2016.

Lynch, Ennis Ray, Jr. "C# Object Pooling." CodeProject. N.p., 12 Oct. 2007. Web. 29 Nov. 2016.

Nystrom, Robert. "Object Pool." Game Programming Patterns. Genever Benning, 2 Nov. 2014. Web. 29 Nov. 2016.

"Object Pool Pattern." Object Oriented Design. N.p., n.d. Web. 02 Dec. 2016.

Shvets, Alexander. "Object Pool." Design Patterns Explained Simply. SourceMaking, 31 July 2015. Web. 29 Nov. 2016.

Scarterfield, Jeff. "Goomba." How to Draw Cartoons Online. Web. 29 Nov. 2016.