我应该如何重构此代码?

How Should I Move Forward With Refactoring This Code?

所以我正在开发一个副项目网络应用程序,它可以让您在一个网站上跟踪来自多家公司的包裹。即您可以输入任何跟踪号码,服务器将检查它的格式并吐出适当的跟踪信息。

Click here to see my file directory!

我决定采用 策略模式 门面 ,因为我认为这将有助于应用很好。

以上是我当前的回购。

结构为:

Client -> DeliveryFacade -> DeliveryController -> TrackingInterface -> Various Company API's (FedEx, CanadaPost, UPS)。

我目前正在研究 DeliveryController,并且在我研究它时遇到了一些臭代码。

就是这个:

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*/;
    }

我的问题是:有什么方法可以消除每个策略的明显重复吗?

如果我想从新类型的公司添加新的跟踪编号格式,我必须在我的跟踪策略文件夹中添加一个新的 class,然后我必须将案例添加到 checkFormat 和过程(显然未完成)。

是否可以使用某种形式的抽象来避免这种情况?

您忘记提及您正在使用 TypeScript。

我会这样做:

interface IDeliveryCompany {
     tackingNumberMatch(trackingNumber: string): boolean;
     process(): void;
}

class UPSDeliveryCompany implements IDeliveryCompany {

     trackingNumberMatch(trackingNumber: string): boolean {
         return /{regex}/.test(trackingNumber);
     }

     process(): void {
          // ... do the processing
     }
}

// ... similar other delivery companies ...

class DeliveryCompanyFactory {

    private _companies: Array<IDeliveryCompany>;

    constructor() {
        _companies = [
            new UPSDeliveryCompany(),
            new CanadaPostDeliveryCompany(),
            new FedExDeliveryCompany()
        ];
    }

    getCompany(trackingNumber: string): IDeliveryCompany {
        return this._companies.find((c) => c.trackingNumberMatch(trackingNumber));
    }
}

/// example usage:
const factory = new DeliveryCompanyFactory();
factory.getCompany("some_tracking_number").process();

这样,当你需要添加一个新的快递公司时,你将不得不为其创建一个新的class,它将封装该快递公司的所有逻辑,并添加一个它的实例DeliveryCompanyFactory.

如果您有一些对所有快递公司通用的逻辑,那么您可以将 IDeliveryCompany 接口替换为具有通用逻辑的 DeliveryCompany 基础 class。