Scenario
Let's say that there is an entity in my domain called Shop
. As a shop owner (user), I am able to create rewards that customer users will be able to exchange.
It also could be possible to have some kind of reward creation policy (eg. a maximum number of rewards that as store owner I can create: if that value is 4 -> I won't be able to add more than 4 rewards to my store).
Reward creation (for a shop)
Considering the following 1-to-N relationship: Shop (1)->(N) Reward, what would be the most appropriate way to manage rewards (taking into account that Shop
would have a list of Reward
's)?
In case there was any reward policy that could be somehow abstracted out by a IRewardCreationPolicy
interface and used where needed:
interface IRewardCreationPolicy {
isAllowed(shop: Shop);
}
Below are some design alternatives that I am taking into consideration.
Alternative #1
Reward
management is fully handled by the Shop
class:
class Reward {
/* props, methods... */
}
class Shop {
private id: number;
private name: string;
private rewards: Reward[];
constructor(rewardCreationPolicy: IRewardCreationPolicy) {}
addReward(reward: Reward): void {
if (!this.rewardCreationPolicy.isAllowed(this)) {
// throw exception
}
this.rewards.push(reward);
}
removeReward(id: number): void {
/* Remove reward with the given id */
}
}
class AddRewardUseCase {
constructor(shopStorage: IShopStorage) {}
execute(request: AddRewardRequest) {
const shop = this.shopStorage.findById(request.shopId);
shop.addReward(request.reward);
this.shopStorage.update(shop);
}
}
Alternative #2
Reward management is fully handled outside the Shop
class:
class Reward {
/* props, methods... */
}
class Shop {
private id: number;
private name: string;
private rewards: Reward[];
constructor() {}
getRewards(): Reward[] {
return this.rewards;
}
}
class AddRewardUseCase {
constructor(
shopStorage: IShopStorage,
rewardCreationPolicy: IRewardCreationPolicy
) {}
execute(request: AddRewardRequest) {
const shop = this.shopStorage.findById(request.shopId);
if (!this.rewardCreationPolicy.isAllowed(shop)) {
// throw exception
}
shop.getRewards().push(request.reward);
this.shopStorage.update(shop);
}
}
Questions
In this case there is class (Shop
) that holds a list of objects (Reward
's). Should any possible action on this list be encapsulated inside the holder class? In this case, I assume that if we had any other list aside from the rewards it would be also managed by the holder itself too.
I understand that we would be talking about encapsulation here, so in that case I guess the Alternative #1 would be the best choice. What are your thoughts on this?