Luis Valencia
Luis Valencia

Reputation: 33988

How to use abstract classes in typescript

I am trying to port (in a reduced manner) the following sample to typescript, as I want to DEMO the abstract factory pattern in typescript.

https://gerardnico.com/wiki/lang/java/dao

So far the code I have created is the following (structure only)

export default class Customer{
    public id: string;
    public firstName: string;
    public lastName: string;
}


import Customer from "./Customer";

export default interface ICustomerDAO{
    insertCustomer(): number;
    deleteCustomer(): boolean;
    findCustomer(): Customer;
    updateCustomer(): boolean;
    listCustomers(): Customer[];
}


import CustomerDAO from "./ICustomerDAO";
import SharepointListDAOFactory from "./SharepointListDAOFactory";
import JsonDAOFactory from "./JsonDAOFactory";


export default abstract class DAOFactory{
    public static SHAREPOINTLIST: number = 1;
    public static REMOTEJSON : number = 2;

    public abstract getCustomerDAO(): CustomerDAO;

    public  getDAOFactory(whichFactory: number): DAOFactory {

      switch (whichFactory) {
        case 1: 
            return new SharepointListDAOFactory();
        case 2: 
            return new JsonDAOFactory();      
        default  : 
            return null;
      }
    }
}


import DAOFactory from "./DAOFactory";
import ICustomerDAO from "./ICustomerDAO";
import JsonCustomerDAO from "./JsonCustomerDAO";


export default class JsonDAOFactory extends DAOFactory{
    getCustomerDAO(): ICustomerDAO{
        return new JsonCustomerDAO();
    }
}

import DAOFactory from "./DAOFactory";
import ICustomerDAO from "./ICustomerDAO";
import SharepointCustomerDao from "./SharepointCustomerDAO";

export default class SharepointListDAOFactory extends DAOFactory{

    getCustomerDAO(): ICustomerDAO{
        return new SharepointCustomerDao();
    }
}

import ICustomerDAO from "./ICustomerDAO";
import Customer from "./Customer";

//actual implementation
export default class JsonCustomerDAO implements ICustomerDAO{

    public insertCustomer(): number{
        return 1;
    }

    public deleteCustomer(): boolean{
        return true;
    }

    public findCustomer(): Customer{
        return new Customer();
    }

    public updateCustomer(): boolean{
        return true;
    }

    public listCustomers(): Customer[]{
        let c1= new Customer();
        let c2= new Customer();
        let list: Array<Customer> = [c1, c2 ];
        return list;
    } 
}

import ICustomerDAO from "./ICustomerDAO";
import Customer from "./Customer";

//actual implementations
export default class SharepointCustomerDao implements ICustomerDAO{

    public insertCustomer(): number{
        return 1;
    }

    public deleteCustomer(): boolean{
        return true;
    }

    public findCustomer(): Customer{
        return new Customer();
    }

    public updateCustomer(): boolean{
        return true;
    }

    public listCustomers(): Customer[]{
        let c1= new Customer();
        let c2= new Customer();
        let list: Array<Customer> = [c1, c2 ];
        return list;
    } 
}

Code compiles, but I am having issues in how to use the abstract class, from the client or caller of the above code, which is an SPFx REACT component

import * as React from 'react';
import styles from './TypescriptDesignPatterns02AbstractFactory.module.scss';
import { ITypescriptDesignPatterns02AbstractFactoryProps } from './ITypescriptDesignPatterns02AbstractFactoryProps';
import { escape } from '@microsoft/sp-lodash-subset';
import { ITypescriptDesignPatterns02AbstractFactoryState } from './ITypescriptDesignPatterns02AbstractFactoryState';
import SharepointListDAOFactory from './Factory/SharepointListDAOFactory';
import DAOFactory from './Factory/DAOFactory';

export default class TypescriptDesignPatterns02AbstractFactory extends React.Component<ITypescriptDesignPatterns02AbstractFactoryProps, ITypescriptDesignPatterns02AbstractFactoryState> {
  constructor(props: ITypescriptDesignPatterns02AbstractFactoryProps, state: ITypescriptDesignPatterns02AbstractFactoryState) {
    super(props);
    this.setInitialState();
  }

  public render(): React.ReactElement<ITypescriptDesignPatterns02AbstractFactoryProps> {
    switch(this.props.datasource) {
      case "Sharepoint":
        let sharepointlistdaofactory: SharepointListDAOFactory =   DAOFactory.getDAOFactory(1);



        break;
      case "JSON":
        break;
    }
    return null;
  }

  public setInitialState(): void {
    this.state = {
      items: []
    };
  }



}

I am not sure about the syntax or how to translate these lines to typescript

DAOFactory OracleDbFactory =   
  DAOFactory.getDAOFactory(DAOFactory.DAOORACLEDB); 

// Create a DAO
CustomerDAO custDAO = 
  OracleDbFactory.getCustomerDAO();

Upvotes: 1

Views: 1712

Answers (1)

Explosion Pills
Explosion Pills

Reputation: 191729

Currently your code would require instantiation of a DAOFactory to have acess to the getDAOFactory method:

const daoFactory = new DAOFactory;

However you can't do this since DAOFactory is abstract.

Instead the factory function doesn't need to be an object method -- it can be a class method (static) or even just a function.

const getDAOFactory = (whichFactory: number): DAOFactory => {
  switch (whichFactory) {
    case 1: 
        return new SharepointListDAOFactory();
    case 2: 
        return new JsonDAOFactory();      
    default  : 
        return null;
  }
}

Now you can just call OracleDbFactory = getDAOFactory(DAOFactory.DAOORACLEDB); (type is implicit from the return type of the function).

I do wonder why you need this extra layer of abstraction though. Seems like something like custDao = getDao(DaoTypes.Customer) would suffice.

Upvotes: 1

Related Questions