NOTE
Simple Factory Pattern
Simple-factory notes in Java and Go, followed by a generic template-method + simple-factory + strategy example.
This is a historical learning note and may contain outdated or incomplete understanding.
Separate class creation from class use.
1. Java
1.1. Client
public class Client
{
public static void main(String[] args)
{
Car car = CarFactory.getCart("Audi");
}
}
1.2. Products
public interface Car
{
}
public class AudiCar implements Car
{
}
public class QQCar implements Car
{
}
1.3. Factory
public class CarFactory
{
public static Car getCart(String name)
{
// The problem is that this introduces too many if/else branches
if("Audi".equals(name))
return new AudiCar();
else if ("QQ".equals(name))
return new QQCar();
else
throw new RuntimeException("No such car");
}
}
2. Golang
2.1. Products
/* Car interface */
type Car interface {
Run()
}
// QQ car
type QQCar struct {
}
func (Q QQCar) Run() {
fmt.Println("I am QQ car")
}
// Audi car
type AodiCar struct {
}
func (Q AodiCar) Run() {
fmt.Println("I am Aodi car")
}
2.2. Factory
/* A simple factory can be implemented as a constructor function */
func NewCar(name string) Car {
if name == "QQ" {
return &QQCar{}
} else if name == "Aodi" {
return &AodiCar{}
} else {
return nil
}
}
2.3. Client
func main() {
qqCar := simplefactory.NewCar("QQ")
aodiCar := simplefactory.NewCar("Aodi")
qqCar.Run()
aodiCar.Run()
}
3. Example
Template Method + Simple Factory + Strategy Pattern

- pb.go
package pb
type Request struct {
}
type Response struct {
}
- abstract_template.go
package template
import (
"context"
"fmt"
"example/template/pb"
)
/* Implements IFetchDataService */
type abstractFetchDataService struct {
IFetchDataSteps // internal processing steps
req *pb.Request
rsp *pb.Response
basicInfo interface{} // basic data
extraInfo interface{} // extra data
}
func (t *abstractFetchDataService) checkParam(ctx context.Context) error {
fmt.Println("default checkParam")
return nil
}
func (t *abstractFetchDataService) getBasicInfo(ctx context.Context) error {
fmt.Println("default getBasicInfo")
return nil
}
func (t *abstractFetchDataService) getExtraInfo(ctx context.Context) error {
fmt.Println("default getExtraInfo")
return nil
}
//newTemplate
func newTemplate(iSteps IFetchDataSteps) *abstractFetchDataService {
return &abstractFetchDataService{IFetchDataSteps: iSteps}
}
/* Fixed steps of the template method */
func (t *abstractFetchDataService) HandleRequest(ctx context.Context, req *pb.Request, rsp *pb.Response) error {
t.req = req
t.rsp = rsp
if err := t.IFetchDataSteps.checkParam(ctx); err != nil {
return err
}
if err := t.IFetchDataSteps.getBasicInfo(ctx); err != nil {
return err
}
if err := t.IFetchDataSteps.getExtraInfo(ctx); err != nil {
return err
}
return nil
}
- source_a_template_impl.go
package template
import (
"context"
"fmt"
)
const TypeSourceAService = 2
var sourceAServiceConstructorFunc fetchDataServiceConstructor = func() IFetchDataService {
return NewFetchDataFromSourceAService()
}
func init() {
GlobalServiceFactory.RegisterService(TypeSourceAService, sourceAServiceConstructorFunc)
}
/* source_a service */
type FetchDataFromSourceAService struct {
*abstractFetchDataService
}
func (f *FetchDataFromSourceAService) checkParam(ctx context.Context) error {
fmt.Println("checkParam")
return f.abstractFetchDataService.checkParam(ctx)
}
func (f *FetchDataFromSourceAService) getBasicInfo(ctx context.Context) error {
fmt.Println("getBasicInfo")
return f.abstractFetchDataService.getBasicInfo(ctx)
}
//func (f *FetchDataFromSourceAService) getExtraInfo(ctx context.Context) error {
// fmt.Println("getExtraInfo")
// return f.abstractFetchDataService.getExtraInfo(ctx)
//
//}
//NewFetchDataFromSourceAService
func NewFetchDataFromSourceAService() *FetchDataFromSourceAService {
service := &FetchDataFromSourceAService{}
service.abstractFetchDataService = newTemplate(service)
return service
}
- factory.go
package template
import "fmt"
var GlobalServiceFactory = newServiceFactory()
// Custom function type used to create service instances
type fetchDataServiceConstructor = func() IFetchDataService
// service function factory
type serviceFactory struct {
serviceMap map[int]fetchDataServiceConstructor
}
//newServiceFactory
func newServiceFactory() *serviceFactory {
return &serviceFactory{serviceMap: make(map[int]fetchDataServiceConstructor)}
}
// Get a service by service type
func (s *serviceFactory) GetServiceByType(serviceType int) (IFetchDataService, error) {
serviceConstructor, ok := s.serviceMap[serviceType]
if ok {
return serviceConstructor(), nil
}
err := fmt.Errorf("GetServiceByType: serviceType %v invalid", serviceType)
return nil, err
}
// Register serviceType and serviceConstructor
func (s *serviceFactory) RegisterService(serviceType int, serviceConstructor fetchDataServiceConstructor) {
s.serviceMap[serviceType] = serviceConstructor
}
- itemplate.go
package template
import (
"context"
"example/template/pb"
)
/* External interface for fetching a data list */
type IFetchDataService interface {
HandleRequest(ctx context.Context, req *pb.Request, rsp *pb.Response) error
}
/* Internal processing steps */
type IFetchDataSteps interface {
// validate parameters
checkParam(ctx context.Context) error
// fetch basic data
getBasicInfo(ctx context.Context) error
// fetch extra data
getExtraInfo(ctx context.Context) error
}
- template_test.go
package template
import (
"context"
"testing"
)
func TestTemplate(t *testing.T) {
service, _ := GlobalServiceFactory.GetServiceByType(TypeSourceAService)
service.HandleRequest(context.Background(), nil, nil)
}
// output
checkParam
default checkParam
getBasicInfo
default getBasicInfo
default getExtraInfo
Discussion
Sign in with GitHub to comment. Discussions are stored as GitHub Issues.View on GitHub