A discussion came up today discussing how the factory pattern looks in certain languages, and I found myself thinking about how it might look in Ruby. A quick Google resulted in an example that seemed to violate part of the reason for the Factory Pattern in the first place (there was a distinct factory for every subclass?), so I decided to ponder my own contrived example to refresh my knowledge.

## Factory Pattern Contrived Example: Shapes

One example that I quickly thought of (but quickly became useless beyond three sides) was a factory that got an instance of a `Shape`

subclass when given a variable number of sides. Ultimately, a `Triangle`

can have its perimeter and area determined if only the lengths of the sides are known, but any shape beyond that needs either diagonals or angles specified. So I settled on the factory producing either a `Triangle`

that could report back an `area`

or a `perimeter`

or a generic `Polygon`

(arbitrarily excluding `Triangle`

from this) that would only report back `perimeter`

and `raise`

an `InterdeterminateArea`

if the `area`

was requested.

## No `new`

s is Good `new`

s

A hallmark of the factory pattern is blocking instantiation directly on the target classes (in this case, making `new`

`protected`

so that only classes within the hierarchy can access it. If our `.new`

method is properly `protected`

, then we should receive a `NoMethodError`

calling `.new`

. (It is enough to `assert`

that `NoMethodError`

is raised because otherwise, all classes should respond to `.new`

:

## The `MiniTest`

cases

```
require 'minitest/autorun'
require_relative 'shape_factory'
class TestShapeFactory < MiniTest::Unit::TestCase
def test_triangle
triangle=Shape.get_shape(3,3,3)
assert_in_epsilon(3.89, triangle.area, 0.01)
assert_equal(9, triangle.perimeter)
assert_instance_of(Triangle, triangle)
end
def test_polygon
polygon=Shape.get_shape(4,4,4,4)
assert_equal(16, polygon.perimeter)
assert_raises(IndeterminateArea) {polygon.area}
assert_instance_of(Polygon, polygon)
end
def test_new_shape
assert_raises(NoMethodError) {Triangle.new}
assert_raises(NoMethodError) {Polygon.new}
assert_raises(NoMethodError) {Shape.new}
end
end
```

Above we have are testing that `get_shape`

with 3 arguments returns a `Triangle`

that can return an `area`

(using `assert_in_epsilon`

because the result is irrational) and a `perimeter`

. `test_polygon`

tests that a shape with 4 sides returns a `Polygon`

that can correctly return a `perimeter`

but raises an `InterdeterminateArea`

when `#area`

is called. Finally, `test_new_shape`

validates that we have correctly blocked `.new`

calls on `Shape`

, `Polygon`

, and `Triangle`

.

`shape_factory.rb`

```
class Shape
# be sure to protect {class}.new, not instance.new
class << self
protected :new
end
def self.get_shape(*sides)
case sides.length
when 3
Triangle.new(*sides)
else
Polygon.new(*sides)
end
end
def perimeter
@perimeter ||= @sides.inject(:+)
end
def area
raise 'not implemented'
end
def initialize(*sides)
@sides = sides
end
end
class Triangle < Shape
def area
# Heron's Formula
Math.sqrt(perimeter/2.0*(@sides.map {|s| perimeter/2.0 - s}.inject(:*)))
end
end
class IndeterminateArea < StandardError; end
class Polygon < Shape
def area
raise IndeterminateArea
end
end
```

Ultimately, `Polygon`

could probably be collapsed into `Shape`

and only return `Triangle`

. Of course, implementations of shapes with more sides could be made to provide area, but they would require providing additional information to `get_shape`

that might expose the need for the sender to have an awareness of implementation details. Another option might be to pass the successive vertices of the polygon which might allow deeper inferring of how to calculate meaningful information from the shape, but this example is a start with a factory pattern implementation that can be expanded as necessary.