jeudi 14 juin 2018

Design Pattern for inheriting a specific property/method, depending on a given condition

I am currently working on a project using Typescript and KnockoutJS.

I have a base class that handles form validation, communicating with the server, and edit permissions.

The child classes create the observables and assign them to the correct data fields.

  class SlotViewModel extends BaseViewModel {
    public safetyLevels = ko.computed(() => {
      let safetyLevelOptions = ko.observableArray();
      safetyLevels.forEach((val: string) => {
        let safetyLevel  = new Level(val, this.FormatSafetyLevel(val));
        safetyLevelOptions.push( safetyLevel );
      });

      return safetyLevelOptions();
    });
    // Option Selection
    public careLevels = ko.computed(() => {

      let careLevelOptions = ko.observableArray();
      careLevels.forEach((val: string) => {
        let careLevel  = new Level(val, this.FormatCareLevel(val));
        careLevelOptions.push( careLevel );
      });

      return careLevelOptions();
    });

    // Slot Model Properties
    public name = ko.observable(this.modelData.name);
    public description = ko.observable(validator.unescape(this.modelData.desc));
    public deviceType = ko.observable(this.modelData.deviceType);
    public area = ko.observable(this.modelData.area);
    public drr = ko.observable(this.modelData.drr);
    public arr = ko.observable(this.modelData.arr);
    public safetyLevel = ko.observable(this.modelData.safetyLevel);
    public careLevel = ko.observable(this.modelData.careLevel);

    // Care Level
    public careLevelFormatted = ko.computed(() => {
      return this.FormatCareLevel(this.careLevel());
    });
    // Safety Level
    public safetyLevelDisplay = ko.computed(() => {
      return this.FormatSafetyLevel(this.safetyLevel());
    });

    protected editURI = `${basePath}/slots/${slot.id}/`;

    constructor(modelData: webapi.Slot) {
      super(modelData);
    }

    protected alteredData(): {} {
      return {
        name: this.name(),
        desc: this.description(),
        deviceType: this.deviceType(),
        area: this.area(),
        drr: this.drr(),
        arr: this.arr(),
        careLevel: this.careLevel(),
        safetyLevel: this.safetyLevel(),
      };
    };

    protected updateFields(data: webapi.Slot) {
      // Update View after server alterations
      this.name(data.name);
      this.description(validator.unescape(data.desc));
      this.deviceType(data.deviceType);
      this.area(data.area);
      this.drr(data.drr);
      this.arr(data.arr);
      this.careLevel(data.careLevel);
      this.safetyLevel(data.safetyLevel);

      super.updateFields(data);
    }

    /**
     * Compute Display for given Care Level
     *
     * @param {string} careLevel Name of.
     */
    private FormatCareLevel(careLevel: string) {
      let newVal = careLevel.toLowerCase();
      return newVal[0].toUpperCase() + newVal.substr(1);
    }

    /**
     * Compute Display for given Safety Level
     *
     * @param {string} safetyLevel Name of safety level.
     */
    private FormatSafetyLevel(safetyLevel: string) {

      let newVal;
      switch (safetyLevel) {
        case 'NONE':
          newVal = 'None';
          break;
        case 'CONTROL':
          newVal = 'Control';
          break;
        case 'CREDITED':
          newVal = 'Credited Control';
          break;
        case 'CONTROL_ESH':
          newVal = 'Control with ESH Impact';
          break;
        case 'CREDITED_ESH':
          newVal = 'Credited Control with ESH Impact';
          break;
        case 'CREDITED_PPS':
          newVal = 'Credited Control Personnel Protection System';
          break;
        default:
          newVal = safetyLevel;
      }

      return newVal;
    }
  }

alteredData() and updateFields are for the base class to use before and after it has sent data to the server (updated the model).

alteredData: tells the base class what fields have been edited.

updateFields: tells the ViewModel what changes the server made to the data after sanitization.

My current issue is this: FormatSafetyLevel, Format CareLevel, safetyLevels, careLevels, safetyLevelDisplay, and careLevelDisplay are all pretty object specific.

I have a class that does not implement careLevel or safetyLevel at all. I have another object that implements safetyLevel.

I am looking for a good design pattern that will allow me to use the above functions when specified.

Is there a good way to inherit specific methods/properties from a Base class only when specified?

If not, is there a recommended approach I should use? I am not sure if I should just bite the bullet and just re-write all the safetyLevel methods and properties in my other class that needs them.

I have been searching the internet and can not find a good approach or design pattern that tackles this issue.

I tried typescript Mixins but was just getting declaration errors, plus I don't like the way they are used.

I was thinking about passing a parameter to the base class that specifies whether safetyLevel or careLevel is used and defining properties and methods accordingly withing the constructor, but I am not sure if that is a good approach.

Any help is much appreciated! Thanks!

Aucun commentaire:

Enregistrer un commentaire