From harness-claude
Implements the Builder pattern with fluent API and director classes. Useful for constructing complex objects with many optional parameters, or building different representations from the same construction process.
How this skill is triggered — by the user, by Claude, or both
Slash command
/harness-claude:gof-builder-patternThe summary Claude sees in its skill listing — used to decide when to auto-load this skill
> Construct complex objects step-by-step using fluent builders and director classes.
Construct complex objects step-by-step using fluent builders and director classes.
build() time, not during individual settersFluent builder with TypeScript (most common pattern):
interface QueryConfig {
table: string;
conditions: string[];
orderBy?: string;
limit?: number;
offset?: number;
joins: string[];
}
class QueryBuilder {
private config: Partial<QueryConfig> = { conditions: [], joins: [] };
from(table: string): this {
this.config.table = table;
return this;
}
where(condition: string): this {
this.config.conditions!.push(condition);
return this;
}
join(clause: string): this {
this.config.joins!.push(clause);
return this;
}
orderBy(column: string): this {
this.config.orderBy = column;
return this;
}
limit(n: number): this {
this.config.limit = n;
return this;
}
offset(n: number): this {
this.config.offset = n;
return this;
}
build(): string {
if (!this.config.table) throw new Error('Table is required');
let query = `SELECT * FROM ${this.config.table}`;
if (this.config.joins!.length > 0) {
query += ` ${this.config.joins!.join(' ')}`;
}
if (this.config.conditions!.length > 0) {
query += ` WHERE ${this.config.conditions!.join(' AND ')}`;
}
if (this.config.orderBy) query += ` ORDER BY ${this.config.orderBy}`;
if (this.config.limit !== undefined) query += ` LIMIT ${this.config.limit}`;
if (this.config.offset !== undefined) query += ` OFFSET ${this.config.offset}`;
return query;
}
}
// Usage
const query = new QueryBuilder()
.from('users')
.join('LEFT JOIN orders ON orders.user_id = users.id')
.where('users.active = true')
.where('users.age > 18')
.orderBy('users.created_at DESC')
.limit(20)
.offset(40)
.build();
Immutable result via build():
class EmailBuilder {
private to: string[] = [];
private subject = '';
private body = '';
private cc: string[] = [];
private attachments: Buffer[] = [];
addTo(address: string): this {
this.to.push(address);
return this;
}
withSubject(subject: string): this {
this.subject = subject;
return this;
}
withBody(body: string): this {
this.body = body;
return this;
}
addCC(address: string): this {
this.cc.push(address);
return this;
}
addAttachment(data: Buffer): this {
this.attachments.push(data);
return this;
}
build(): Readonly<Email> {
if (this.to.length === 0) throw new Error('At least one recipient required');
if (!this.subject) throw new Error('Subject is required');
return Object.freeze({
to: [...this.to],
subject: this.subject,
body: this.body,
cc: [...this.cc],
attachments: [...this.attachments],
});
}
}
Director class (for reusable construction sequences):
class ReportDirector {
constructor(private builder: ReportBuilder) {}
buildSummaryReport(): void {
this.builder
.setTitle('Summary Report')
.addSection('Overview')
.addSection('KPIs')
.setFooter('Confidential');
}
buildDetailedReport(): void {
this.builder
.setTitle('Detailed Report')
.addSection('Executive Summary')
.addSection('Data Analysis')
.addSection('Charts')
.addSection('Raw Data')
.addSection('Appendix')
.setFooter('Confidential');
}
}
Why not just use an options object? Options objects work well for simple configs, but builders shine when:
build()Anti-patterns:
build() — freeze the resultbuild()TypeScript step builder (enforce required fields at compile time):
// Forces callers to provide required fields before optional ones
interface NeedsTable {
from(table: string): NeedsCondition;
}
interface NeedsCondition {
where(cond: string): NeedsCondition;
build(): string;
limit(n: number): NeedsCondition;
}
class TypeSafeQueryBuilder implements NeedsTable, NeedsCondition {
private table = '';
private conditions: string[] = [];
private limitVal?: number;
from(table: string): NeedsCondition {
this.table = table;
return this;
}
where(cond: string): NeedsCondition {
this.conditions.push(cond);
return this;
}
limit(n: number): NeedsCondition {
this.limitVal = n;
return this;
}
build(): string {
return `SELECT * FROM ${this.table} WHERE ${this.conditions.join(' AND ')}`;
}
static create(): NeedsTable {
return new TypeSafeQueryBuilder();
}
}
// Compile error if you skip from()
const q = TypeSafeQueryBuilder.create().from('users').where('active = true').build();
refactoring.guru/design-patterns/builder
npx claudepluginhub intense-visions/harness-engineering --plugin harness-claudeGuides applying the Builder pattern to simplify construction of complex objects with many parameters, reducing telescoping constructors.
Generates Builder pattern for PHP 8.4 classes with fluent interface, validation, optional director, and unit tests. For complex objects with many parameters or optional fields.
Guides Java generics usage for type-safe reusable code, covering type parameters, wildcards, bounds, generic classes, and methods.