Skip to content

Instantly share code, notes, and snippets.

@CharlieDigital
Last active April 2, 2022 23:59
Show Gist options
  • Select an option

  • Save CharlieDigital/1a60bf5e8410f6cac37eef6488b8d245 to your computer and use it in GitHub Desktop.

Select an option

Save CharlieDigital/1a60bf5e8410f6cac37eef6488b8d245 to your computer and use it in GitHub Desktop.
Code listing showing object-oriented techniques for using structural logic
class Product {
constructor(
public readonly name: string,
public readonly weight: number,
public readonly isLiquid: boolean = false
) { }
}
type ShippingMethod = 'USPS' | 'UPS' | 'FedEx' | 'DHL'
abstract class ShippingStrategy {
constructor(
public readonly weight: number,
public readonly hasLiquid: boolean
) { }
// The default is that there is no surcharge
get surcharge(): number {
return 1;
}
// An abstract method has no body; it defines a contract
// that an inheriting class has to fulfill.
protected abstract calculate(): number;
getShippingPrice() {
const price = this.calculate() * this.surcharge;
console.log(`Calculated shipping cost: ${price}`); // We can add centralized logic
return price
}
}
class UspsShippingStrategy extends ShippingStrategy {
calculate(): number {
let price;
if (this.weight < 2) {
price = 1.50;
}
else if (this.weight < 10) {
price = 4.00;
}
else {
price = 10.00;
}
return price;
}
override get surcharge(): number {
return this.hasLiquid ? 1.25 : 1;
}
}
class UpsShippingStrategy extends ShippingStrategy {
calculate(): number {
let price
if (this.weight < 4) {
price = 2.00;
}
else {
price = 12.00;
}
return price;
}
}
class FedExShippingStrategy extends ShippingStrategy {
calculate(): number {
return 0; // Exercise for the reader
}
}
class DhlShippingStrategy extends ShippingStrategy {
calculate(): number {
return 0; // Exercise for the reader
}
}
const shippingStrategies:
Record<ShippingMethod, {
new(weight: number, hasLiquid: boolean): ShippingStrategy
}> = {
USPS: UspsShippingStrategy,
UPS: UpsShippingStrategy,
FedEx: FedExShippingStrategy,
DHL: DhlShippingStrategy
}
class Order {
constructor(
public readonly products: Product[],
public readonly shippingMethod: ShippingMethod
) { }
calculateShippingCost(): number {
// Calculate the total weight.
const weight = this.products.reduce(
(previous, current) => previous + current.weight, 0
);
// Determine if we have a liquid
const hasLiquid = this.products.some(p => p.isLiquid);
const StrategyConstructor = shippingStrategies[this.shippingMethod];
const strategy = new StrategyConstructor(weight, hasLiquid);
return strategy.getShippingPrice();
}
}
const cart = [
new Product('Microwave Popcorn', 1),
new Product('Cooking Oil', 4, true),
new Product('Chocolate Bar', 2)
]
const order = new Order(cart, 'USPS');
console.log(order.calculateShippingCost());
// Run with:
// tsc -t es5 delivery.ts
// node delivery.js
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment