Creating a connection between a class Bill and a class SimplifiedBill: Best practices

As stated in the title, I am faced with a situation where I have two classes: SimplifiedBill, which includes only date and finalPayment, and Bill, which has the same properties as SimplifiedBill but also additional details such as taxes, user data, and services.

One possible solution could be for Bill to inherit from SimplifiedBill. However, I believe this approach may not be conceptually accurate because SimplifiedBill is essentially derived from Bill; therefore, Bill does not inherit anything from SimplifiedBill.

Do you have any suggestions on how to design the classes in this scenario?

EDIT: The process works as follows.
I retrieve a list of SimplifiedBill objects from the backend. When I select one of these objects, I then fetch the corresponding Bill from the API to view its details.

In case you are curious, I am using Angular. I have a ListComponent (or view) that displays my SimpleBill objects. Clicking on an object takes me to the DetailComponent, where I can view the specific Bill. Unfortunately, when transitioning between views, I am unable to transfer the entire SimpleBill object; I can only pass its ID or another field.

Answer №1

I completely agree that inheriting from SimplifiedBill would be conceptually inaccurate. In my opinion, it's best to use inheritance sparingly and with caution as it is often misused.

Instead of using inheritance, I suggest taking a compositional approach. For example, if Bill contains SimplifiedBill, a more sensible solution could be creating a data structure for Bill that includes properties for the details:

let bill = {
  details: {...},
  simplifiedBill: {...}
}

Although I used a simple object in this example (which is suitable considering you are working with javascript), the same concept can also be applied to a class-based approach. You may want to consider choosing a different name for the simplified bill, such as "summary".

Overall, it's commendable that you recognized the limitations of using inheritance in this scenario.

Answer №2

It's possible that a relationship isn't necessary in this case; it seems like the SimplifiedBill class is more of a basic representation of the Bill class.

One approach could be to maintain the separation of the two classes and introduce a third class, such as a SimplifiedBillFactory, which takes a Bill object and generates a SimplifiedBill.

For example (pseudo code, may not be valid typescript!)

export class SimplifiedBillFactory
{

  createSimplifiedBill(bill: Bill) : SimplifiedBill
  {
     return new SimplifiedBill{
             billId=bill.Id,
             date=bill.date,
             finalPayment=bill.calculateFinalPayment()
     };         
   }
}

An advantage of this method is that if you need to add more details to SimplifiedBill later on (such as additional aggregates like total line item count), it can easily be done within this class. It also promotes keeping the specific behaviors of a bill within the Bill class itself and accessing them through methods (e.g. the calculateFinalPayment method on Bill).

You could alternatively use a factory method within the Bill class instead of creating a separate factory class, but personally I prefer to keep them distinct. This allows for flexibility in adding other classes in the future alongside the Bill class for generating instances of SimplifiedBill.

Answer №3

This is a thought-provoking question,

When it comes to Inheritance, it's important to consider the relationship as an "is-a" connection. Before establishing an inheritance relationship between two entities, ask yourself if entity A can truly be categorized as entity B.

  • Here's the first question to ponder: What defines the simplest form of a Bill or what are the essential components that every Bill must possess? Knowing this will ultimately define what a Bill should encompass.

If we reason that SimpleBill is essentially a type of Bill, then items belonging to SimpleBill collectively formulate a Bill. According to popular opinion, a Bill at its most basic level might comprise solely of a billId. Thus, a barebones representation of Bill may look like:

interface Bill{
    billId: string;
}
  • The second query arises: Is VerboseBill essentially a SimpleBill or vice versa? This assessment will clarify whether an inheritance relationship exists between them.

Rather than labeling SimpleBill as a subset of VerboseBill or vice versa, it seems more appropriate to conclude that they do not share an inheritance relation;

Considering potential future variations such as AaaBill{taxes}, BbbBill{services}..., do these new iterations inherit from one another? Despite their differences, all these variations ultimately stem from being labeled as Bill!

In light of the above discussion, here is a proposed solution:

export interface SimpleBill extends Bill{
  date: number;
  finalPayment: number;

}

export interface VerboseBill extends Bill{
    date: number;
    finalPayment: number;
    taxes:number;
    services;...
    userData;...
}

export namespace Bill{

    export function simplify(bill:Bill): SimpleBill{
        return {id: bill.id, date: bill.date, finalPayment: bill.finalPayment};
    }

    export function verbose(bill:Bill): VerboseBill{
        if((bill as VerboseBill).taxes !==undefined){
            return bill as VerboseBill;
        }
        return fetchVerboseBill(bill.id);
    }
}

export namespace SimpleBill{
    export const verbose = Bill.verbose
}

export namespace VerboseBill{
    export const simplify = Bill.simplify
}

Similar questions

If you have not found the answer to your question or you are interested in this topic, then look at other similar questions below or use the search

Node OOM Error in Webpack Dev Server due to Material UI Typescript Integration

Currently in the process of upgrading from material-ui v0.19.1 to v1.0.0-beta.20. Initially, everything seems fine as Webpack dev server compiles successfully upon boot. However, upon making the first change, Node throws an Out of Memory error with the fol ...

"Utilize Ajax and PHP to seamlessly upload a PDF file directly into a MYSQL database

I am trying to figure out how to upload a pdf file from user input into my MySQL database. I have provided code that displays a user registration form with the option to upload a PDF file. My goal is to use AJAX to post this data to a PHP script for storag ...

Encountering a 500 error while attempting to send data to an API route within a Laravel web page using XMLHttpRequest at http://127:8000/api/v1/exemp. Can anyone

let requestData = { products: [ { description: "product1", barcode: "123456", price: 10, note: "note1" }, { description: "product2", barcode: "654321", price: 20, note: "note2" ...

Is it possible to trim a video using HTML code?

I am trying to find a way to crop a video using HTML 5. <video id="glass" width="640" height="360" autoplay> <source src="invisible-glass-fill.mp4" type="video/mp4"> </video> Currently, the video has a resolution of 640x360. However ...

Mapping strings bidirectionally in Typescript

I am currently working on a two-way string mapping implementation; const map = {} as MyMap; // need the correct type here const numbers = "0123456789abcdef" as const; const chars = "ghijklmnopqrstuv" as const; for (let i = 0; i < n ...

Leverage generic types and allow acceptance of objects with arbitrary keys

Is it possible to allow the Use function argument type to accept any unknown key, as well as correctly type the keys from SomeGeneric? function Example (opt: { valid?: boolean }) { } type SomeGeneric = Parameters<typeof Example>[0] function Use(op ...

Using jQuery idle timeout to abort jQuery AJAX calls in Laravel 5.2

Currently, I have implemented the jQuery Idle Timeout plugin in my Laravel 5.2 system. Everything works perfectly on my local setup using MAMP Pro, but upon uploading it to the development server, I encountered an "Aborted" error in the AJAX get request: ...

The component is rendering properly, however the router-outlet in Angular seems to be getting overlooked

I've set up a router-outlet in app.component.html, admin.component.html, and manage-users.component.html. However, I'm facing an issue where the router-outlet in manage-users.component.html is not showing anything when I navigate to http://localh ...

Laravel error 500 (Internal Server Error) is encountered when making an ajax post request

I've already added the csrf token to my view and I'm still getting an error. I've searched everywhere for a solution, but all I find is to add the csrf token, which I've already done. What should I do next? <meta name="_token" conte ...

Creating gifs from an array of base64 strings with gifshot doesn't seem to function properly on Firefox browsers

I am currently attempting to utilize the gifshot library from here in order to generate gifs from a canvas. The process involves capturing the canvas using canvas.toDataURL(), then storing these results in an array, which is subsequently passed to the gifs ...

Confirm that a specific value exists within an enumerated set

I am currently using Angular 13.3.9 and typescript 4.6.4. My main objective is to determine if a value is referencing an enum. Below is the code snippet: export enum HttpFunctionalErrorCodes { ACCOUNT_NOT_FOUND = 'ACCOUNT_NOT_FOUND', USER_ ...

Substitute all items identified by a particular tag with a component

Is it possible to replace elements with React? I am interested in replacing all elements with a specific tag with an input field when an event like clicking an 'edit' button occurs. I have experience doing this with jQuery, but I would prefer us ...

Guide to developing a manual tally counter with recorded logs using HTML and JavaScript

I am currently in need of assistance with creating a manual input counter using the App Script Editor. My website design already includes a single input textbox, a reset button, and a disabled box. What I would like to achieve is that when I enter a numb ...

Ensure that each class element contains a value before using jQuery to toggle the disabled class

I'm having trouble validating the values of the input elements in my form. I can't seem to figure out what I'm doing wrong. Can anyone help me out? Thank you. <div class="form--group"> <input class="thename" name="name[]" type= ...

Vue appears to be having trouble waiting for the axios Post request

While testing a login request, I encountered an issue where jest did not call the mock: This is my test : const User = '123123' jest.mock('axios', () => ({ get: jest.fn(), post: (_url, _body) => new Promise((resolve, reject ...

Take out a specific element from an array consisting of multiple objects

I have a specific array structure and I need to remove elements that match a certain criteria. Here is the initial array: const updatedUsersInfo = [ { alias: 'ba', userId: '0058V00000DYOqsQAH', username: '<a href=" ...

"The error message "Node JS, MYSQL connection.query is not a valid method" indicates

db_config.js: const mysql = require('mysql'); var connection = mysql.createConnection({ host: 'localhost', user: 'root', password: '', database: 'test' }) connection.connect(function(err) ...

Unexpected results are being produced in React due to code, functions are not being executed upon pressing the submit button

Whenever I click on the Upload button without entering the country code and selecting a file, it displays an alert requesting to "please enter the code and choose the file". However, once I input these fields and then click on the Upload button, this metho ...

One click wonder: Easily print any webpage content with just the click of a button!

For example, upon clicking the button on my webpage, I want the content of another page to be sent directly to a printer. The objective is to bypass the print dialog box and print preview that typically appears when using the browser's default printin ...

Changing the key name for each element in an array using ng-repeat: a guide

In my current project, I have an array of objects that I am displaying in a table using the ng-repeat directive. <table> <thead> <tr> <th ng-repeat="col in columnHeaders">{{col}}</th> //['Name&apo ...