Skip to content

Factory ​

The factory pattern has different variations, called factory, creation method, static creation/factory method, simple factory, factory method or abstract factory (see factory comparison by Shvets (n.d.)).

In this article, the simple factory is described.

Intent ​

The simple factory pattern is described as an with creation method that instantiates a new object based on passed parameters.

Structure ​

At first a creation function finds a component based on criteria. Any returned component implements the same signature.

#/components/-user-profile.ts
ts
import { UserType, type User } from "#/domain/user";
import { ComponentLike } from "@glint/template";

interface UserProfileSignature {
  Args: {
    user: User;
  };
}

export function createProfile(type: UserType): ComponentLike<UserProfileSignature> {
  switch (type) {
    case UserType.User:
      return User;
    case UserType.Customer:
      return Customer;
    case UserType.Admin:
      return Admin;
    default:
      throw new Exception("Wrong user type passed.");
  }
}

Using the bare factory pattern is enough with {{#let}}

#/components/user-profile.gts
glimmer-ts
import { createProfile, type UserProfileSignature } from '#/components/-user-profile';
import type { TOC } from '@ember/component/template-only';

const UserProfile: TOC<UserProfileSignature> = <template>
  {{#let (createProfile (@user.type)) as |Profile|}}
    {{! do sth with `Profile` }}

    <Profile @user={{@user}}/>
  {{/let}}
</template>

You may decide to yield that component or invoke it in place. As much as <UserProfile> implements the UserProfileSignature so would any of the created components.

Invoking the component:

hbs
<UserProfile @user={{@user}} />

The <UserProfile> component becomes the simple factory by using the type of a User object to distinguish which specific subcomponent to "create".

Applicability ​

  • Use it to create components to an object that has a dynamic type.
  • Perfectly usable on a list/stream of those objects.

References ​