Skip to content

Instantly share code, notes, and snippets.

@thiagoadsix
Created June 6, 2024 02:37
Show Gist options
  • Save thiagoadsix/85085763062990ab2fc3238343dcb20e to your computer and use it in GitHub Desktop.
Save thiagoadsix/85085763062990ab2fc3238343dcb20e to your computer and use it in GitHub Desktop.
This is will be a part of my code that I had to implement Strategy design pattern
import {
AssessmentMeasures,
AssessmentResult,
BodyMeasurement,
GenderType,
} from "@domain/shared/entities/types";
export abstract class AssessmentAbstract {
abstract calculateResults(
input: AssessmentAbstract.Input
): AssessmentAbstract.Output;
protected calculateAge(birthDateString: string): number {
const birthDate = new Date(birthDateString);
const today = new Date();
let age = today.getFullYear() - birthDate.getFullYear();
const monthDiff = today.getMonth() - birthDate.getMonth();
if (
monthDiff < 0 ||
(monthDiff === 0 && today.getDate() < birthDate.getDate())
) {
age--;
}
return age;
}
protected calculateSumOfSkinfolds(
assessmentMeasures: AssessmentMeasures,
skinfoldSites: string[]
): number {
return skinfoldSites.reduce((sum, prop) => {
return sum + assessmentMeasures[prop];
}, 0);
}
protected calculateBodyMetrics(
sumOfSkinfolds: number,
age: number,
coefficients: { a: number; b: number; c: number; d?: number }
): { bodyDensity: number; bodyFatPercentage: number } {
let bodyDensity;
if (coefficients.d !== undefined) {
bodyDensity =
coefficients.a -
coefficients.b * sumOfSkinfolds +
coefficients.c * Math.pow(sumOfSkinfolds, 2) -
coefficients.d * age;
} else {
bodyDensity =
coefficients.a - coefficients.b * sumOfSkinfolds + coefficients.c * age;
}
const bodyFatPercentage = (4.95 / bodyDensity - 4.5) * 100;
return {
bodyDensity: Number(bodyDensity.toFixed(2)),
bodyFatPercentage: Number(bodyFatPercentage.toFixed(2)),
};
}
protected calculateBMR(
gender: GenderType,
weight: number,
height: number,
age: number
): number {
if (gender === "male") {
return 66 + 13.7 * weight + 5 * height - 6.8 * age;
} else {
return 655 + 9.6 * weight + 1.8 * height - 4.7 * age;
}
}
protected calculateFatMass(
weight: number,
bodyFatPercentage: number
): number {
return weight * (bodyFatPercentage / 100);
}
protected calculateLeanMass(weight: number, fatMass: number): number {
return weight - fatMass;
}
protected calculateIdealBodyFat(gender: GenderType): {
min: number;
max: number;
} {
if (gender === "male") {
return { min: 8, max: 20 };
} else {
return { min: 15, max: 30 };
}
}
protected calculateIdealWeight(
leanMass: number,
idealBodyFat: { min: number; max: number }
): {
min: number;
max: number;
} {
const minWeight = leanMass / (1 - idealBodyFat.min / 100);
const maxWeight = leanMass / (1 - idealBodyFat.max / 100);
return { min: minWeight, max: maxWeight };
}
}
export namespace AssessmentAbstract {
export type Input = {
assessmentType: string;
assessmentMeasures?: AssessmentMeasures;
bodyMeasurement?: BodyMeasurement;
gender: GenderType;
birthDate: string;
};
export type Output = AssessmentResult | null;
}
import {
AssessmentResult,
AssessmentType,
} from "@domain/shared/entities/types";
import { PhotosImpl } from "./implementations/photos.impl";
import { Pollock3Impl } from "./implementations/pollock-3.impl";
import { Pollock7Impl } from "./implementations/pollock-7.impl";
import { AssessmentAbstract } from "./assessment.abstract";
export class AssessmentStrategy {
private strategies: Map<AssessmentType, AssessmentAbstract>;
constructor() {
this.strategies = new Map();
this.strategies.set("photos", new PhotosImpl());
this.strategies.set("pollock_3", new Pollock3Impl());
this.strategies.set("pollock_7", new Pollock7Impl());
}
run(input: AssessmentStrategy.Input): AssessmentStrategy.Output {
const strategy = this.strategies.get(
input.assessmentType as AssessmentType
);
if (!strategy) {
throw new Error(
`Assessment type (${input.assessmentType}) is not supported.`
);
}
if (
input.assessmentType === "pollock_3" ||
input.assessmentType === "pollock_7"
) {
if (!input.assessmentMeasures || input.assessmentMeasures == null) {
throw new Error(
`Assessment measures are required for ${input.assessmentType}.`
);
}
}
return strategy.calculateResults(input);
}
}
export namespace AssessmentStrategy {
export type Input = AssessmentAbstract.Input;
export type Output = AssessmentResult | null;
}
import { AssessmentAbstract } from "../assessment.abstract";
export class PhotosImpl extends AssessmentAbstract {
calculateResults(input: AssessmentAbstract.Input): AssessmentAbstract.Output {
const { assessmentMeasures } = input;
if (assessmentMeasures) {
const { birthDate, gender } = input;
const age = this.calculateAge(birthDate);
const bmr = this.calculateBMR(
gender,
assessmentMeasures.weight,
assessmentMeasures.height,
age
);
const idealBodyFat = this.calculateIdealBodyFat(gender);
return {
bmr,
idealBodyFatMax: idealBodyFat.max,
idealBodyFatMin: idealBodyFat.min,
};
}
return null;
}
}
import {
FEMALE_3_COEFFICIENTS,
MALE_3_COEFFICIENTS,
} from "@domain/shared/constants";
import { AssessmentAbstract } from "../assessment.abstract";
export class Pollock3Impl extends AssessmentAbstract {
calculateResults(input: AssessmentAbstract.Input): AssessmentAbstract.Output {
const { gender, birthDate, assessmentMeasures } = input;
const genderSpecificProps =
gender === "male"
? ["chest", "abdomen", "thigh"]
: ["triceps", "suprailiac", "thigh"];
const coefficients =
gender === "male" ? MALE_3_COEFFICIENTS : FEMALE_3_COEFFICIENTS;
const sumOfSkinfolds = this.calculateSumOfSkinfolds(
assessmentMeasures,
genderSpecificProps
);
const age = this.calculateAge(birthDate);
const metrics = this.calculateBodyMetrics(
sumOfSkinfolds,
age,
coefficients
);
const bmr = this.calculateBMR(
gender,
assessmentMeasures.weight,
assessmentMeasures.height,
age
);
const fatMass = this.calculateFatMass(
assessmentMeasures.weight,
metrics.bodyFatPercentage
);
const leanMass = this.calculateLeanMass(assessmentMeasures.weight, fatMass);
const idealBodyFat = this.calculateIdealBodyFat(gender);
const idealWeight = this.calculateIdealWeight(leanMass, idealBodyFat);
return {
bodyDensity: metrics.bodyDensity,
bodyFatPercentage: metrics.bodyFatPercentage,
sumOfSkinfolds,
bmr,
fatMass,
leanMass,
idealBodyFatMin: idealBodyFat.min,
idealBodyFatMax: idealBodyFat.max,
idealWeightMin: idealWeight.min,
idealWeightMax: idealWeight.max,
};
}
}
import { AssessmentResult } from "@domain/shared/entities/types";
import {
FEMALE_7_COEFFICIENTS,
MALE_7_COEFFICIENTS,
} from "@domain/shared/constants";
import { AssessmentAbstract } from "../assessment.abstract";
export class Pollock7Impl extends AssessmentAbstract {
calculateResults(input: AssessmentAbstract.Input): AssessmentResult {
const { gender, birthDate, assessmentMeasures } = input;
const genderSpecificProps =
gender === "male"
? [
"chest",
"abdomen",
"thigh",
"subscapular",
"axilla",
"calf",
"triceps",
]
: [
"triceps",
"suprailiac",
"thigh",
"subscapular",
"axilla",
"calf",
"abdomen",
];
const coefficients =
gender === "male" ? MALE_7_COEFFICIENTS : FEMALE_7_COEFFICIENTS;
const sumOfSkinfolds = this.calculateSumOfSkinfolds(
assessmentMeasures,
genderSpecificProps
);
const age = this.calculateAge(birthDate);
const metrics = this.calculateBodyMetrics(
sumOfSkinfolds,
age,
coefficients
);
const bmr = this.calculateBMR(
gender,
assessmentMeasures.weight,
assessmentMeasures.height,
age
);
const fatMass = this.calculateFatMass(
assessmentMeasures.weight,
metrics.bodyFatPercentage
);
const leanMass = this.calculateLeanMass(assessmentMeasures.weight, fatMass);
const idealBodyFat = this.calculateIdealBodyFat(gender);
const idealWeight = this.calculateIdealWeight(leanMass, idealBodyFat);
return {
bodyDensity: metrics.bodyDensity,
bodyFatPercentage: metrics.bodyFatPercentage,
sumOfSkinfolds,
bmr,
fatMass,
leanMass,
idealBodyFatMin: idealBodyFat.min,
idealBodyFatMax: idealBodyFat.max,
idealWeightMin: idealWeight.min,
idealWeightMax: idealWeight.max,
};
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment