动态生成并返回类对象

发布于 2025-02-13 06:24:45 字数 846 浏览 3 评论 0原文

在我的数据库中,我有一个product_type('prod1'|'prod2'|'prod3')。

我想根据其类型生成类对象。

这是我的打字稿代码:

interface Product {
  readonly type: string;
  name(): string;
}

class Product1 implements Product {
  readonly type: string = 'prod1';
  name: () => 'Product 1';
}
class Product2 implements Product {
  readonly type: string = 'prod2';
  name: () => 'Product 2';
}
class Product3 implements Product {
  readonly type: string = 'prod3';
  name: () => 'Product 3';
}

function getProductByType(type: string) {
  // TODO: return Product1, Product2 or Product3
  if (type == 'prod1') return new Product1();
  else if (type == 'prod2') return new Product2();
  else return new Product3();
}

问题在于getProductbyType函数。 是否有一种方法可以根据传递的类型返回混凝土产品类而没有多个IF-ELSE语句?

这听起来像是出厂策略模式的好情况,但我不知道如何在此处正确实施它...

In my database I have a product_type ('prod1' | 'prod2' | 'prod3').

I would like to generate a class object based on its type.

Here's my TypeScript code:

interface Product {
  readonly type: string;
  name(): string;
}

class Product1 implements Product {
  readonly type: string = 'prod1';
  name: () => 'Product 1';
}
class Product2 implements Product {
  readonly type: string = 'prod2';
  name: () => 'Product 2';
}
class Product3 implements Product {
  readonly type: string = 'prod3';
  name: () => 'Product 3';
}

function getProductByType(type: string) {
  // TODO: return Product1, Product2 or Product3
  if (type == 'prod1') return new Product1();
  else if (type == 'prod2') return new Product2();
  else return new Product3();
}

The problem is in the getProductByType function.
Is there an approach to return a concrete Product class based on the passed type without having multiple if-else statements?

This sounds like a good case for a factory strategy pattern but I can't figure out how to correctly implement it here...

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

森罗 2025-02-20 06:24:45

有几种可能的解决方案,取决于解决方案应该是多少“自动化”。

1)简单

使用映射,类似于Adityaparab的答案。


class Product1 {}
class Product2 {}
class Product3 {}

// Mapping from type name to class object.
const ProductMap = {
  prod1: Product1,
  prod2: Product2,
  prod3: Product3
};

function getProductByType(type) {
    const Product = ProductMap[type];
    if (!Product) throw new Error(`Unknown ProductType '${type}'.`);
    return new Product(type);
}

console.log(getProductByType("prod1"));

2)真实反射(需要打字稿变压器)

stackblitz demo

查看 tst-reflection github repo。

用于标记产品课程的装饰商。

/**
 * Decorator used to mark Product classes.
 * @reflect - required JSDoc property. Means all decorated types can be used in reflection.
 * @param productType
 */
export function ForProductType(productType: string) {
  return (ctor: Function) => {};
}

装饰产品课。

@ForProductType('prod1')
export class Product1 implements Product {
  readonly type: string = 'prod1';

  get name() {
    return 'Product 1';
  }
}

getProductbyType功能具有一点点反射。

// Some reflection job.. Find all types decorated by the ForProductType decorator and create map of those types.
const entries = Type.getTypes()
  .map<[string, Type]>((type) => [
    type
      .getDecorators()
      .find((decorator) => decorator.name == 'ForProductType')
      ?.getArguments()[0],
    type,
  ])
  .filter(([typeName, type]) => !!typeName);
const ProductTypeMap = new Map<string, Type>(entries);

function getProductByType(type: string): Promise<Product> {
  const ProductType: Type = ProductTypeMap.get(type);

  if (!ProductType) {
    throw new Error(`Unknown ProductType '${type}'.`);
  }

  return ProductType.getCtor().then((Product) => new Product());
}

用法

getProductByType('prod1').then((product) => console.log(product, product.name));

它返回承诺,因为它可以进行产品类的动态导入。

There are several possible solutions, it depends how much "automated" the solution should be.

1) Simple

Using mapping, similar to AdityaParab's answer.


class Product1 {}
class Product2 {}
class Product3 {}

// Mapping from type name to class object.
const ProductMap = {
  prod1: Product1,
  prod2: Product2,
  prod3: Product3
};

function getProductByType(type) {
    const Product = ProductMap[type];
    if (!Product) throw new Error(`Unknown ProductType '${type}'.`);
    return new Product(type);
}

console.log(getProductByType("prod1"));

2) Real Reflection (requires TypeScript transformer)

StackBlitz demo here.

Check out tst-reflection GitHub repo.

Decorator used to mark Product classes.

/**
 * Decorator used to mark Product classes.
 * @reflect - required JSDoc property. Means all decorated types can be used in reflection.
 * @param productType
 */
export function ForProductType(productType: string) {
  return (ctor: Function) => {};
}

Decorated Product class.

@ForProductType('prod1')
export class Product1 implements Product {
  readonly type: string = 'prod1';

  get name() {
    return 'Product 1';
  }
}

getProductByType function with a little bit of reflection.

// Some reflection job.. Find all types decorated by the ForProductType decorator and create map of those types.
const entries = Type.getTypes()
  .map<[string, Type]>((type) => [
    type
      .getDecorators()
      .find((decorator) => decorator.name == 'ForProductType')
      ?.getArguments()[0],
    type,
  ])
  .filter(([typeName, type]) => !!typeName);
const ProductTypeMap = new Map<string, Type>(entries);

function getProductByType(type: string): Promise<Product> {
  const ProductType: Type = ProductTypeMap.get(type);

  if (!ProductType) {
    throw new Error(`Unknown ProductType '${type}'.`);
  }

  return ProductType.getCtor().then((Product) => new Product());
}

Usage

getProductByType('prod1').then((product) => console.log(product, product.name));

It returns Promise cuz it does dynamic imports of the Product classes.

从此见与不见 2025-02-20 06:24:45

为什么不考虑使用构造函数?

interface IProduct {
  readonly type: string;
  name(): string;
}

const PRODUCT_MAPPING: any = {
  prod1: "Product 1",
  prod2: "Product 2",
  prod3: "Product 3"
};

class Product implements IProduct {
  constructor(public readonly type: string) {}
  name(): string {
    return PRODUCT_MAPPING[this.type];
  }
}

function getProductByType(type: string): Product {
  return new Product(type);
}

const p1 = getProductByType("prod1");
console.log(p1.name()); // Product 1

const p2 = getProductByType("prod2");
console.log(p2.name()); // Product 2

const p3 = getProductByType("prod3");
console.log(p3.name()); // Product 3

Why not consider using a constructor?

interface IProduct {
  readonly type: string;
  name(): string;
}

const PRODUCT_MAPPING: any = {
  prod1: "Product 1",
  prod2: "Product 2",
  prod3: "Product 3"
};

class Product implements IProduct {
  constructor(public readonly type: string) {}
  name(): string {
    return PRODUCT_MAPPING[this.type];
  }
}

function getProductByType(type: string): Product {
  return new Product(type);
}

const p1 = getProductByType("prod1");
console.log(p1.name()); // Product 1

const p2 = getProductByType("prod2");
console.log(p2.name()); // Product 2

const p3 = getProductByType("prod3");
console.log(p3.name()); // Product 3
~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文