So I'm working on a side-project web-application that lets you track packages from multiple companies on one website. i.e. you can enter any tracking number and the server will check the format of it and spit out the appropriate tracking information.
Click here to see my file directory!
I've decided to move forward with a strategy pattern, and a facade, because I think it would serve the purpose of the application well.
Above is my current repo.
The structure would be:
Client -> DeliveryFacade -> DeliveryController -> TrackingInterface -> Various Company API's (FedEx, CanadaPost, UPS).
I'm currently working on DeliveryController, and encountered some smelly code, as I was working on it.
This is it:
export default class DeliveryController{
/** Checks the format of tracking number to determine the shipping company it
* has been given. If the tracking number is able to be validated, then return
* the correct shipping company. If it is not able to be validated (not a string), return
* null.
*
* @params trackingNumber : string
* @return shippingCompany : string
*
* e.g. returns "Fedex" , "CanadaPost", "UPS"
* */
public checkFormat(trackingNumber : string) : string{
if (typeof trackingNumber == "string" || trackingNumber instanceof String) {
// CanadaPost
if (/{regex}/.test(trackingNumber)){
return "CanadaPost";
}
// FedEx
if (/{regex}/.test(trackingNumber)) {
return "FedEx";
}
// UPS
if (/{regex}/.test(trackingNumber)) {
return "UPS";
}
}
else return null;
}
/** Processes a tracking number and returns a deliveryInfo.
* @param trackingNumber
* @return deliveryInfo
*/
public process(trackingNumber : string) : deliveryInfo{
var company = this.checkFormat(trackingNumber);
switch (company){
case "CanadaPost":
break;
case "FedEx":
break;
case "UPS":
break;
}
return /*some deliveryInfo*/;
}
My question is this: is there some way that I can eliminate the obvious repetition of each strategy?
If I want to add a new tracking number format from a new type of company, I have to add a new class in my tracking strategy folder, and then I have to add the cases to checkFormat and process (which is obviously unfinished).
Is there some form of abstraction that I can use to avoid this?
You forgot to mention that you are using TypeScript.
I would do something like that:
That way, when you need to add a new delivery company, you will have to create a new class for it, which will encapsulate all the logic of that delivery company, and add a instance of it to the
DeliveryCompanyFactory
.If you have some logic which is common for all delivery companies, then you can replace the
IDeliveryCompany
interface with aDeliveryCompany
base class which will have the common logic.