GridItem and GridContainer
General

Task

In my opinion you lost the focus of your task description:


   [...]storing items into an inventory. The container is based on a grid as well as the items going into that container.


The word container can easily be replaced by inventory:


   [...] storing items into an inventory. The inventory is based on a grid as well as the items going into that inventory.


The goal is to store items in an Inventory/Container but currently it stores Shapes instead of Items:


  public class RectangleContainer implements GridContainer {

  /* ... */
  private final Map&lt;GeoPoint, GridShape&gt; content;

  /* ... */

  @Override
  public boolean fitsInside(GridShape shape, GeoPoint location) { /* ... */ }

  /* ... */

  @Override
  public void add(GridShape shape, GeoPoint location) { /* ... */ }


}



What is an Item

 What an Item currently is


  public class RectangleItem&lt;I&gt; implements GridShape, ItemHolder&lt;I&gt; { /* ... */}



To make it simpler to discuss:


  public class Item&lt;I&gt; implements Shape, ItemHolder&lt;I&gt; { /* ... */}



Is Item an Item? When I see only the class name I would say yes, but after looking on the signature I would say: "It could be". 
From the signature it is an item that is a shape that holds an item.
Is it an item that holds an other item?

What an Item should be

A Item is something that has a Shape.


  public class Item&lt;I&gt; {

    private I value;
    private Shape shape;

    public Item(I value, Shape shape) { /* ... */ }

}



and an ìtem should be packed into an inventory/container:

public class RectangleContainer implements GridContainer {
    /* ... */
    @Override    public void add(Item item, GeoPoint location) {/* ... */}
}


Code Smell

Feature Envy

Inside RectangleContainer#fitsInside(GridShape shape, GeoPoint location) is the following line:

Collection&lt;GeoPoint&gt; relativeShape = shape.getRelativeShape(location);


The relativeShape gets passed into hasIntersection and isInBounds of RectangleContainer:


  @Override
public boolean fitsInside(GridShape shape, GeoPoint location) {
  Collection&lt;GeoPoint&gt; relativeShape = shape.getRelativeShape(location);
  boolean hasIntersections = hasIntersection(relativeShape);
  boolean isInBounds = isInBounds(relativeShape);
  return !hasIntersections &amp;&amp; isInBounds;
}



Because RectangleContainer works with the internals of shape (relativeShape) it is a feature envy.

You could return a custom object PositionedItem that has the methods intersectsNotInside(inventory) and isInBoundOf(inventory):

@Override
public boolean fitsInside(Item item, GeoPoint location) {
   PositionedItem positionedItem = shape.at(location);
   return !positionedItem.intersectsNotInside(this) &amp;&amp; positionedItem.isInBoundOf(this);
}


The benefit will be that you will not have duplicate logic for hasIntersections and isInBounds in the different subtypes of GridContainer.

Redundant Public

In both interfaces GridContainer and GridShape you have used the key word public. Per default are fields in an interface are public.

Also valid java:

public interface GridShape {
    boolean fitsInside(GridContainer container, GeoPoint pointer);
    Collection&lt;GeoPoint&gt; getShape();
    GeoPoint getPointer();
    Collection&lt;GeoPoint&gt; getRelativeShape(GeoPoint point);
}


Everything is addable


  @Override
public void add(GridShape shape, GeoPoint location) {
   content.put(location, shape);
}



I could add a shape, that is 1000 times bigger as a RectangleContainer..

The adding of a shape should be checked so that it is not possible to at wrong shapes