Factories
Key takeaways
IFactory | Interface that defines methods used by component factories. |
Factory | Basic factory class that is used to create components via registered types and factory functions. |
Default factories | Factories that are built-into the Pip.Services toolkit, which can be used to create some of the most common component types. |
CompositeFactory | Component that is used to group multiple factories into a single component. |
Introduction
This tutorial will teach you how to create factories for custom components, and how to use Pip.Service’s default factories to create instances of components already included in the toolkit. We will first examine the IFactory interface and its relations with the Factory and CompositeFactory components. Then, we will learn how to create a factory that helps build custom components and how to use the default factories to create components already included in the toolkit. Next, we will see how to create a composite factory that groups several factories together. Finally, we will review all the concepts learned.
IFactory
This interface declares methods that are required by factories to create components. The factories implementing this interface identify components by locators, which are usually defined by descriptors.
This interface is implemented by both the Factory and CompositeFactory classes. The diagram below shows their relations:
Factory
This class represents a basic factory that creates components using registered types and factory functions.
To understand how this class works, we will use an example where we create a factory and then use it to create a custom component. The following sections will take us step-by-step through the construction of such a program.
Pre-requisites
In order to create a factory, we need to import the Factory class. This can be done with the following import statement:
import { Factory } from "pip-services4-components-node";
import (
cbuild "github.com/pip-services4/pip-services4-go/pip-services4-components-go/build"
)
from pip_services4_components.build import Factory
Custom component
Next, we create a basic custom component. This component includes the myTask() method, which will be used later on in this tutorial. The code below shows what this class looks like:
export class MyComponent1 {
private _status: string;
/**
* Creates a new instance of the component.
*/
public constructor() {
this._status = "Created";
console.log("MyComponent1 has been created.");
}
public async myTask() {
console.log("task executed")
}
}
import (
"fmt"
)
type MyComponent1 struct {
_status string
}
func NewMyComponent1() *MyComponent1 {
c := &MyComponent1{}
c._status = "Created"
fmt.Println("MyComponent1 has been created.")
return c
}
func MyTask() {
fmt.Println("task executed")
}
class MyComponent1():
def __init__(self):
"""
Creates a new instance of the component.
"""
self._status = "Created"
print("MyComponent1 has been created.")
def myTask(self):
print("task executed")
Factory and component creation
Once we have our custom component defined, we create a factory for it by defining an instance of the Factory class. Next, we register our component within the factory instance and we use the factory’s create() method to create an instance of our custom component. The following code shows how to do this:
let factory = new Factory();
factory.registerAsType(new Descriptor("mygroup", "mycomponent1", "default", "*", "1.0"), MyComponent1);
let component1 = factory.create(new Descriptor("mygroup", "mycomponent1", "default", "name1", "1.0"));
factory := cbuild.NewFactory()
factory.RegisterType(cref.NewDescriptor("mygroup", "mycomponent1", "default", "*", "1.0"), NewMyComponent1)
component1, err = factory.Create(cref.NewDescriptor("mygroup", "mycomponent1", "default", "name1", "1.0"))
from pip_services4_components.refer import Descriptor
factory = Factory()
factory.register_as_type(Descriptor("mygroup", "mycomponent1", "default", "*", "1.0"), MyComponent1)
component1 = factory.create(Descriptor("mygroup", "mycomponent1", "default", "name1", "1.0"))
Which, after running, produces the following outcome, confirming that an instance of MyComponent1 has been created.
Once obtained, we can use this instance to, for example, call one of its methods:
component1.myTask();
component1.MyTask()
component1.myTask()
Which, after running, produces the following result:
Default factories
The Pip.Services toolkit contains several factories that can be used to create some common components. These factories are all subclasses of the Factory class. Among them are:
Each of these factories has a set of default descriptors that can be employed to create components from the toolkit. The following table shows the main default factories, components they can create, and those components’ descriptors.
Default factories and component creation
In order to learn how to use the toolkit’s default factories, we’ll explore the procedure for creating a memory lock using the default lock factory. This procedure applies to other default factories and their components as well.
For this, we need to first import the default lock factory. In addition, we need to import the Descriptor class, as we will use it to locate the memory lock. These actions can be done with the following import statements:
import { Factory } from "pip-services4-components-node";
import { DefaultLogicFactory } from "pip-services4-logic-node";
import (
cref "github.com/pip-services4/pip-services4-go/pip-services4-components-go/refer"
clogic "github.com/pip-services4/pip-services4-go/pip-services4-logic-go/build"
)
from pip_services4_logic.lock import DefaultLockFactory
from pip_services4_components.refer import Descriptor
Once we have imported these two components, we can create an instance of the default lock factory.
let lockFactory = new DefaultLogicFactory();
logicFactory := clogic.NewDefaultLogicFactory()
lockFactory = DefaultLockFactory()
And then, we create an instance of MemoryLock by using the corresponding descriptor (see table above).
let lock = lockFactory.create(new Descriptor("pip-services", "lock", "memory", "*", "1.0"));
lock, err := logicFactory.Create(cref.NewDescriptor("pip-services", "lock", "memory", "*", "1.0"))
lock = lockFactory.create(Descriptor("pip-services", "lock", "memory", "*", "1.0"))
We can verify that we have created a memory lock by checking the object’s type. The following command shows how to do this:
typeof(lock)
reflect.TypeOf(lock)
type(lock)
Which, after running, returns the following output:
CompositeFactory
This component allows us to group factories into one entity and then call the one(s) we need independently.
In this section’s example, we will build a component that contains two factories, namely, a factory for the custom component we created in the previous example and a factory for a logger.
Pre-requisites
In order to create a composite factory, we need to import the CompositeFactory class first. This can be done with the following import statement:
import { CompositeFactory } from "pip-services4-components-node";
import (
cbuild "github.com/pip-services4/pip-services4-go/pip-services4-components-go/build"
)
from pip_services4_components.build import CompositeFactory
Composite factory
Once we have imported the class, we can create an instance of it.
let compositeFactory = new CompositeFactory();
compositeFactory := cbuild.NewCompositeFactory()
compositeFactory = CompositeFactory()
Now, we create a factory for the custom component defined in the previous example. Then, we register the component and add its factory to the composite factory. The code below shows how to do this:
import { Descriptor, Factory } from "pip-services4-components-node";
let factory1 = new Factory()
factory1.registerAsType(new Descriptor("mygroup", "mycomponent1", "default", "*", "1.0"), MyComponent1)
compositeFactory.add(factory1)
factory1 := cbuild.NewFactory()
factory1.RegisterType(cref.NewDescriptor("mygroup", "mycomponent1", "default", "*", "1.0"), NewMyComponent1)
compositeFactory.Add(factory1)
from pip_services4_components.build import Factory
from pip_services4_components.refer import Descriptor
factory1 = Factory()
factory1.register_as_type(Descriptor("mygroup", "mycomponent1", "default", "*", "1.0"), MyComponent1)
compositeFactory.add(factory1)
Next, we include a factory for a logger by adding the default logger factory.
import { DefaultLogicFactory } from "pip-services4-logic-node";
compositeFactory.add(new DefaultLogicFactory());
import (
cobserv "github.com/pip-services4/pip-services4-go/pip-services4-observability-go/build"
)
compositeFactory.Add(cobserv.NewDefaultObservabilityFactory())
from pip_services4_observability.log import DefaultLoggerFactory
compositeFactory.add(DefaultLoggerFactory())
Once we’ve added all our factories to the composite factory, we can call the latter to create an instance of our custom component via its descriptor. The following code shows how this can be done:
let component1Locator = new Descriptor("*", "mycomponent1", "*", "*", "1.0");
component1 = compositeFactory.create(component1Locator);
component1Locator := cref.NewDescriptor("*", "mycomponent1", "*", "*", "1.0")
component1, err := compositeFactory.Create(component1Locator)
component1Locator = Descriptor("*", "mycomponent1", "*", "*", "1.0")
component1 = compositeFactory.create(component1Locator)
Which, after running, produces the following result:
Similarly, we can call the same composite factory to create an instance of a logger. The following code shows this step:
let loggerLocator = new Descriptor("*", "logger", "console", "*", "1.0");
let result1 = compositeFactory.create(loggerLocator);
result1
loggerLocator := cref.NewDescriptor("*", "logger", "console", "*", "1.0")
result1, err := compositeFactory.Create(loggerLocator)
loggerLocator = Descriptor("*", "logger", "console", "*", "1.0")
result1 = compositeFactory.create(loggerLocator)
result1
Which, after running, provides the following result that shows that an instance of a logger was created:
Wrapping up
In this tutorial, we have learned how to create a factory that can be used to build a custom component, and how to use Pip.Services’ default factories. We have examined the composite factory, which can be made to include one or more factories and can be called to create instances of components that the included factories are capable of creating.