2022-07-02 15:30:14 +01:00
|
|
|
---
|
2024-02-02 15:58:13 +00:00
|
|
|
categories:
|
2022-08-21 11:00:04 +01:00
|
|
|
- DSA
|
2022-07-02 15:30:14 +01:00
|
|
|
tags:
|
2022-08-21 11:00:04 +01:00
|
|
|
- OOP
|
2022-07-02 15:30:14 +01:00
|
|
|
---
|
|
|
|
|
|
|
|
# Factory pattern
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
The factory pattern pertains to how objects are created in the course of the
|
|
|
|
code. It is class based.
|
2022-07-02 15:30:14 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
In this pattern we create a class interface that delegates the responsibility of
|
|
|
|
object instantiation to its subclasses.
|
2022-07-02 15:30:14 +01:00
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
You have a high level class that sits on top of two or more lower level classes
|
|
|
|
that are semantically related but different in function. Depending on the input
|
|
|
|
the higher level class receives upon instantiation, it will generate one of the
|
|
|
|
lower level classes.
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
### Advantages
|
|
|
|
|
|
|
|
- allows for dynamic creation
|
2024-02-02 15:58:13 +00:00
|
|
|
- we may not know what objects are required until runtime: the factory allows
|
|
|
|
us to cover several eventualities
|
2022-07-02 15:30:14 +01:00
|
|
|
- decoupling
|
2024-02-02 15:58:13 +00:00
|
|
|
- in cases where the lower level classes combine to create something greater
|
|
|
|
than their individual parts (see the Alligator example below), they do not
|
|
|
|
have to know about each other.
|
|
|
|
- maintenance
|
|
|
|
- allows us to add/remove new object classes easily without changing a lot of
|
|
|
|
code.
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
## Examples
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
We have two types of notification: email and push. The creation of these two is
|
|
|
|
handled by a factory class called `NotificationFactory` :
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
```jsx
|
|
|
|
class PushNotification {
|
2024-02-02 15:58:13 +00:00
|
|
|
constructor(sendTo, message) {
|
|
|
|
this.sendTo = sendTo;
|
|
|
|
this.message = message;
|
|
|
|
}
|
2022-07-02 15:30:14 +01:00
|
|
|
}
|
2024-02-02 15:58:13 +00:00
|
|
|
|
2022-07-02 15:30:14 +01:00
|
|
|
class EmailNotification {
|
2024-02-02 15:58:13 +00:00
|
|
|
constructor(sendTo, cc, emailContent) {
|
|
|
|
this.sendTo = sendTo;
|
|
|
|
this.cc = cc;
|
|
|
|
this.emailContent = emailContent;
|
|
|
|
}
|
2022-07-02 15:30:14 +01:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
|
|
|
```jsx
|
|
|
|
class NotificationFactory {
|
2024-02-02 15:58:13 +00:00
|
|
|
createNotification(type, props) {
|
|
|
|
switch (type) {
|
|
|
|
case "email":
|
|
|
|
return new EmailNotification(
|
|
|
|
props.sendTo,
|
|
|
|
props.cc,
|
|
|
|
props.emailContent
|
|
|
|
);
|
|
|
|
case "push":
|
|
|
|
return new PushNotification(props.sendTo, props.message);
|
|
|
|
}
|
|
|
|
}
|
2022-07-02 15:30:14 +01:00
|
|
|
}
|
|
|
|
```
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
We first instantiate an instance of the factory and then pass into it the
|
|
|
|
parameters for either of the two lower level classes.
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
```jsx
|
|
|
|
const factory = new NotificationFactory();
|
2024-02-02 15:58:13 +00:00
|
|
|
|
2022-07-02 15:30:14 +01:00
|
|
|
// create email notification
|
2024-02-02 15:58:13 +00:00
|
|
|
const emailNotification = factory.createNotification("email", {
|
|
|
|
sendTo: "receiver@domain.com",
|
|
|
|
cc: "test@domain.com",
|
|
|
|
emailContent: "This is the email content to be delivered.!",
|
2022-07-02 15:30:14 +01:00
|
|
|
});
|
2024-02-02 15:58:13 +00:00
|
|
|
|
2022-07-02 15:30:14 +01:00
|
|
|
// create push notification
|
2024-02-02 15:58:13 +00:00
|
|
|
const pushNotification = factory.createNotification("push", {
|
|
|
|
sendTo: "receiver-device-id",
|
|
|
|
message: "The push notification message",
|
2022-07-02 15:30:14 +01:00
|
|
|
});
|
|
|
|
```
|
|
|
|
|
2024-02-02 15:58:13 +00:00
|
|
|
This example doesn't use a constructor on the factory class, but we could easily
|
|
|
|
do so. This would remove the need to call a method on the factory class when we
|
|
|
|
want to instantiate one of the subclasses. Here is another example that does
|
|
|
|
this with an alligator factory:
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
```jsx
|
|
|
|
class ReptilePartFactory {
|
|
|
|
constructor(type, props) {
|
2024-02-02 15:58:13 +00:00
|
|
|
if (type === "tail") return new TailFactory(props);
|
|
|
|
if (type === "torso") return new TorsoFactory(props);
|
|
|
|
if (type === "head") return new HeadFactory(props);
|
2022-07-02 15:30:14 +01:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
let alligator = {};
|
|
|
|
let alligatorProps = {
|
2024-02-02 15:58:13 +00:00
|
|
|
tailLength: 2.5,
|
2022-07-02 15:30:14 +01:00
|
|
|
color: "green",
|
2024-02-02 15:58:13 +00:00
|
|
|
snoutLenth: 1,
|
2022-07-02 15:30:14 +01:00
|
|
|
};
|
|
|
|
|
|
|
|
//gets a tail from the tail factory
|
2024-02-02 15:58:13 +00:00
|
|
|
alligator.tail = new ReptilePartFactory("tail", alligatorProps);
|
2022-07-02 15:30:14 +01:00
|
|
|
|
|
|
|
//gets a torso from the torso factory
|
|
|
|
alligator.torso = new ReptilePartFactory("torso", alligatorProps);
|
|
|
|
|
|
|
|
//gets a head from the head factory
|
2024-02-02 15:58:13 +00:00
|
|
|
alligator.head = new ReptilePartFactory("head", alligatorProps);
|
|
|
|
```
|