One idea
A factory is a function or class whose job is to create objects for the rest of your app.
Use it when creation is becoming messy: if-else branches, default values, validation, config, or choosing between similar classes.
Why this matters
In a hackathon app, object creation often starts simple. Then you add UPI and card payments, admin and student users, test data and production config.
If every route, screen, or controller decides how to create these objects, changes become risky. A factory puts that decision in one place.
Do not factory everything
A factory is not needed when you only write new User(name) once and there are no rules around it.
If the factory only hides one simple constructor, it adds noise. Your README should explain the pain it removed, not just name the pattern.
Before: scattered creation
Here is a small TypeScript example from a campus event app. Payment creation is duplicated across routes.
class UpiPayment {
constructor(public upiId: string) {}
pay(amount: number) {
return `Pay ₹${amount} using UPI ${this.upiId}`;
}
}
class CardPayment {
constructor(public last4: string) {}
pay(amount: number) {
return `Pay ₹${amount} using card ending ${this.last4}`;
}
}
function registerForWorkshop(input: any) {
let payment;
if (input.method === "upi") {
payment = new UpiPayment(input.upiId);
} else if (input.method === "card") {
payment = new CardPayment(input.last4);
} else {
throw new Error("Unsupported payment method");
}
return payment.pay(input.amount);
}After: named factory
Now the route asks for a payment object. It does not know the creation rules.
type PaymentMethod = "upi" | "card";
type PaymentInput = {
method: PaymentMethod;
upiId?: string;
last4?: string;
};
class PaymentFactory {
static create(input: PaymentInput) {
if (input.method === "upi") {
if (!input.upiId) throw new Error("UPI ID is required");
return new UpiPayment(input.upiId);
}
if (input.method === "card") {
if (!input.last4) throw new Error("Card last4 is required");
return new CardPayment(input.last4);
}
throw new Error("Unsupported payment method");
}
}
function registerForWorkshop(input: any) {
const payment = PaymentFactory.create(input);
return payment.pay(input.amount);
}Refactor safely
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done
Use AI carefully
Ask AI to find repeated object creation and suggest a factory. Then check the output yourself.
Watch for over-engineering. If it adds abstract classes, interfaces, and folders for one simple object, ask for a smaller version.
Prompt:
Find places in this code where object creation is duplicated or has branching logic. Suggest one simple factory refactor. Keep the public behavior the same.
Check:
- Did it preserve existing inputs and outputs?
- Did it move creation rules into one place?
- Did it avoid extra layers that are not needed?Do this now
Do each one yourself, then tap it to tick it off. The ticks are only a checklist for you: they are not marked or scored.
0 of 5 done