I want to apply the strategy pattern in a microservice where your only responsibility is to take the received payload, validate this payload, adapt the payload and publish it to a database. But I have some variables for this case: I have a context, an origin and an action that will be received in the input payload, following this pattern:
origin: { food, non-food }
context: { cart, order, catalog }
actionCart: { getCart, addItemCart, removeItemCart }
actionOrder: { getOrder, createOrder, getHistory }
actionCatalog: { getCatalog }
data: payload
In short, depending on the origin I will have a context, depending on the context I will have an action, and depending on the action I will have the methods with their adapters and finally publish in the specific database for each call.
I know it's something complex and difficult to understand, so I made a code exemplifying with nested ifs what the code would look like without applying the strategy:
if (food) {
if (context1) {
// all actions publish to database context 1
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank }
if (action3) {
// assemble specific payload and publish it to the bank
}
}
if (context2) {
// all actions publish to database context 2
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank
}
if (action3) {
// assemble specific payload and publish it to the bank
}
}
if (contex3) {
// all actions publish to database 3
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank
}
if (action3) {
// assemble specific payload and publish it to the bank
}
}
}
if (non - food) {
if (context1) {
// all actions publish to database context 1
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank
}
if (action3) {
// assemble specific payload and publish it to the bank
}
}
if (context2) {
// all actions publish to database context 2
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank
}
if (action3) {
// assemble specific payload and publish it to the bank
}
}
if (context3) {
// all actions publish to database context 3
if (action1) {
// assemble specific payload and publish it to the bank
}
if (action2) {
// assemble specific payload and publish it to the bank
}
if (action3) {
// assemble specific payload and publish it to the bank
}
}
}
There is the possibility of applying a strategy for each, for example: strategy for the context and within the context method to have a strategy for the action, but I don't think it's a very good solution.
Can anyone help me with this?
CodePudding user response:
Yeah, you can use Strategy pattern. In addition, it is necessary to use Factory method pattern to resolve payload instances of strategies.
You can choose any strategy at the runtime based on your parameter.
Let me show an example of implementation via TypeScript. So we need some payload types:
type OriginType = 'food' | 'non-food';
And some abstractions that can be implemented by payload strategies:
interface PayloadStrategy {
name: OriginType;
assemblePayload: () => any;
}
abstract class BasePayloadStrategy implements PayloadStrategy {
constructor(public name: OriginType) { }
assemblePayload() {
return `assembled by BasePayloadStrategy`;
}
}
And its concrete implementations:
class FoodPayloadStrategy extends BasePayloadStrategy {
constructor() {
super('food');
}
assemblePayload() {
return `assembled by FoodPayloadStrategy`;
}
}
class NonFoodPayloadStrategy extends BasePayloadStrategy {
constructor() {
super('non-food');
}
assemblePayload() {
return `assembled by NonFoodPayloadStrategy`;
}
}
And it is necessary to implement Factory pattern to generate payload strategies by OriginType:
class PayloadStrategyFactory {
create(type: OriginType) {
switch (type) {
case 'food':
return new FoodPayloadStrategy();
case 'non-food':
return new NonFoodPayloadStrategy();
default:
console.log(`The ${type} strategy is not available.
Falling back to default request strategy.`)
return new FoodPayloadStrategy();
}
}
}
And this is a class which works with PayloadStrategyFactory:
class PayloadClient {
strategyFactory = new PayloadStrategyFactory();
public make(strategyType: OriginType) {
return this.strategyFactory.create(strategyType);
}
}
And then code can be called like this:
const payloadClient = new PayloadClient();
const foodClient = payloadClient.make('food');
console.log(`foodClient`, foodClient)
const nonFoodClient = payloadClient.make('non-food');
console.log(`nonFoodClient`, nonFoodClient)
CodePudding user response:
You can try this:
https://codepen.io/gabrielsodre91/pen/jOzmqJO?editors=0012
const mapper = [
{
origin: 'food', context: 'cart', action: 'addItem',
actionFunction: () => { console.log('Running function for food - card - addItem') },
},
{
origin: 'food', context: 'cart', action: 'removeItem',
actionFunction: () => { console.log('Running function for food - card - removeItem') },
},
{
origin: 'non-food', context: 'order', action: 'createOrder',
actionFunction: () => { console.log('Running function for non-food - order - createOrder') },
},
{
origin: 'non-food', context: 'order', action: 'removeOrder',
actionFunction: () => { console.log('Running function for non-food - order - removeOrder') },
}
];
const payload = { origin: 'non-food', context: 'order', action: 'createOrder' };
const run = mapper.find(e => Object.keys(payload).every(p => payload[p] === e[p]));
run.actionFunction();