# Factory Method and Simple Factories — Design Patterns

Source: https://www.skillbyai.com/en/design-patterns/c-factory

> Centralise the decision of what to create.

## Intent and variants

**Intent:** let one place decide which concrete class to instantiate, so callers depend only on an interface. A **simple factory** is just a function or static method with a `switch` that returns the right implementation; it is not a GoF pattern but is the most common form in practice. The GoF **Factory Method** goes further: a base class defines an abstract creation method and subclasses override it to create different products. **Use it when** the concrete type depends on configuration or input (a storage provider chosen by environment, a parser chosen by file type) and you want that decision in one place. **Avoid it when** there is only one implementation; `new Thing()` is perfectly fine.

## Control how objects are created

Creational patterns hide the details of which class is created and how it is configured.

![Three ideas: factory methods, families of objects, step-by-step construction.](assets/figures/design-patterns/section-2-map.svg) — Figure 2.1 — Simple factory, abstract factory and builder.

## A storage factory

Choosing a file storage backend from configuration.

```typescript
interface FileStorage {
  put(key: string, data: Uint8Array): Promise<void>;
  get(key: string): Promise<Uint8Array | null>;
}

class LocalDiskStorage implements FileStorage { /* writes to a folder */ }
class S3Storage implements FileStorage {
  constructor(private bucket: string) {}
  /* calls the cloud SDK */
}

type StorageConfig =
  | { kind: 'local'; dir: string }
  | { kind: 's3'; bucket: string };

// Simple factory: the only place that knows the concrete classes
export function createStorage(config: StorageConfig): FileStorage {
  switch (config.kind) {
    case 'local': return new LocalDiskStorage(config.dir);
    case 's3':    return new S3Storage(config.bucket);
  }
}

// Callers depend only on the interface
const storage = createStorage(loadConfig().storage);
await storage.put('avatars/42.png', bytes);
```

## Let the type system help

A discriminated union plus an exhaustive switch means the compiler flags every factory that forgets a newly added kind (with strict settings enabled).

**Quiz:** What is the main benefit of a factory for FileStorage?

- [ ] It makes storage faster
- [x] Callers depend on the interface while one place decides the concrete class
- [ ] It removes the need for interfaces
- [ ] It guarantees only one storage instance exists

*Answer:* Callers depend on the interface while one place decides the concrete class. The creation decision is centralised.
