Abstract factory is to provide an interface to create family of related objects without specifying concrete classes. The idea is that the client supplies a set of concrete classes to the factory and then the factory "stamp" the products out. The analogy is like the sheet metal stamping machine. Once the client provides the blueprint for wheels, door, hood, etc., the machine stamps the wheels product, door product, hood product, etc out subsequently.
Here is an example of abstract factory in Go, the ShapeFactory
:
package main
import (
"fmt"
)
const (
CircleID = 0
SquareID = 1
EllipseID = 2
RectangleID = 3
)
// ShapeFactory is an abstract factory for all shapes. It does not have any
// shape data on its own. Rather, it only produces the shape when the client
// provides the necessary shape data.
type ShapeFactory struct {
Circle []byte
Square []byte
Ellipse []byte
Rectangle []byte
}
func (s *ShapeFactory) CreateCurvedShape(shape int) []byte {
switch shape {
case 0:
return s.Circle
case 2:
return s.Ellipse
default:
return nil
}
}
func (s *ShapeFactory) CreateStraightShape(shape int) []byte {
switch shape {
case 1:
return s.Square
case 3:
return s.Rectangle
default:
return nil
}
}
func main() {
// client supplies the models to the factory
s := &ShapeFactory{
Circle: []byte("I'm a circle"),
Square: []byte("I'm a square"),
}
// not all shapes are printed out since client only supply 2 out 4
// concrete shape data.
fmt.Printf("Circle: %v\n", s.CreateCurvedShape(CircleID))
fmt.Printf("Square: %v\n", s.CreateStraightShape(SquareID))
fmt.Printf("Ellipse: %v\n", s.CreateCurvedShape(EllipseID))
fmt.Printf("Rectangle: %v\n", s.CreateStraightShape(RectangleID))
}
Notice that ShapeFactory
does not hold any fixed/concrete values for all 4 shapes at start. It requires client to supply all the shape data upon creation in main
. However, instead of having all the shapes supplying its own data, ShapeFactory
standardizes all shapes creation under 2 functions with ID: CreateCurvedShape
, CreateStraightShape
. That's how abstract factory works: it abstracts the function interfaces even at the absent of the concrete data.