如何设计 class Bill 和 class SimplifiedBill 之间的关系?
How to design relation between a class Bill and a class SimplifiedBill?
所以正如标题提到的,我有 SimplifiedBill
,它只有 date 和 finalPayment,我还有Bill
,它与 SimplifiedBill
具有相同的属性,但也包含所有其他详细信息(税收、用户数据、服务,等等)。
Bill
的解决方案可能是从 SimplifiedBill
继承,但我不认为这在概念上是正确的,因为 SimplifiedBill
是你从 [=13] 中得到的东西=],所以 Bill
不是 "below" SimplifiedBill
,它没有继承任何东西。
关于如何在此处实施 class 设计的任何想法?
编辑:
过程如下。
我有一个从后面获得的 SimplifiedBill
列表,当我单击其中一个时,我请求并从 api 中获得 Bill
并进入详细视图。
如果您想知道,我正在使用 Angular,并且我有一个 ListComponent
(或视图),其中我有我的 SimpleBill
objects ,当我点击其中一个时,我会转到 DetailComponent
,在那里我可以看到特定的 Bill
。当我从一个视图转到另一个视图时,我无法传输 object SimpleBill
,只能传输其 ID(或其他字段)。
不,我同意,从 SimplifiedBill 继承在概念上是不正确的。
一般来说,我认为谨慎使用继承是明智的。我很少看到它被正确使用。
相反,我会推荐一种组合方法:如果 Bill 包含 SimplifiedBill,那么我认为拥有一个具有详细信息属性的数据结构 Bill 是有意义的:
let bill = {
details: {...},
simplifiedBill: {...}
}
请注意,我在这里使用了一个简单的对象(当您使用 javascript 时,它可能也值得考虑),但它同样适用于基于 class 的方法。
不过,您可能想为简化的账单想一个不同的名称。也许像 "summary".
但总的来说,您想到这里可能不太适合的继承概念是件好事。
我倾向于认为你可能甚至不需要这里的关系;听起来 SimplifiedBill
class 更像是 Bill
class.
的简单投影
解决这个问题的一种方法是将两个 class 完全分开,并引入第三个 class,类似于 SimplifiedBillFactory
,需要 [=12] =] 并生成 SimplifiedBill
.
例如(伪代码,可能不是有效的打字稿!)
export class SimplifiedBillFactory
{
createSimplifiedBill(bill: Bill) : SimplifiedBill
{
return new SimplifiedBill{
billId=bill.Id,
date=bill.date,
finalPayment=bill.calculateFinalPayment()
};
}
}
这种方法的一个优点是,如果您需要扩充 SimplifiedBill
以包含更多详细信息(例如可能有一些聚合,例如订单项的总数等),可以在此处轻松完成 class。此外,它鼓励您将法案的实际行为保留在 Bill
class 本身中,并通过方法公开它们(例如 Bill
上的 calculateFinalPayment
方法)
您也可以只在 Bill
class 上使用工厂方法而不是单独的工厂 class,但我个人更愿意将其分开,例如,如果除了 Bill
class 之外,您稍后还需要使用其他 class 来创建您的 SimplifiedBill
实例。
有趣的问题,
继承是一种is-a
关系。当你在它们之间建立继承关系时,问问自己A是不是B。
- 第一个问题:什么是最简单的法案或法案至少应该有什么?答案也回答了
Bill
应该是什么。
由于SimpleBill
也是Bill
的一种,所以SimpleBill
的子集使得Bill
,Bill本身可以简单到只有一个billId(根据评论)。所以 Bill
将是:
interface Bill{
billId: string;
}
- 第二题:
VerboseBill
是SimpleBill
还是相反?,答案也回答了它们之间是否存在继承关系
奇怪的是SimpleBill
是VerboseBill
或者相反,所以他们没有继承关系;
以后你可能还有其他的账单,比如AaaBill{taxes}
,BbbBill{services}
...,他们有继承关系吗?但他们都是 Bill
!
我的建议:
export interface SimpleBill extends Bill{
date: number;
finalPayment: number;
}
export interface VerboseBill extends Bill{
date: number;
finalPayment: number;
taxes:number;
services;...
userData;...
}
export namespace Bill{
export function simplify(bill:Bill): SimpleBill{
return {id: bill.id, date: bill.date, finalPayment: bill.finalPayment};
}
export function verbose(bill:Bill): VerboseBill{
if((bill as VerboseBill).taxes !==undefined){
return bill as VerboseBill;
}
return fetchVerboseBill(bill.id);
}
}
export namespace SimpleBill{
export const verbose = Bill.verbose
}
export namespace VerboseBill{
export const simplify = Bill.simplify
}
所以正如标题提到的,我有 SimplifiedBill
,它只有 date 和 finalPayment,我还有Bill
,它与 SimplifiedBill
具有相同的属性,但也包含所有其他详细信息(税收、用户数据、服务,等等)。
Bill
的解决方案可能是从 SimplifiedBill
继承,但我不认为这在概念上是正确的,因为 SimplifiedBill
是你从 [=13] 中得到的东西=],所以 Bill
不是 "below" SimplifiedBill
,它没有继承任何东西。
关于如何在此处实施 class 设计的任何想法?
编辑:
过程如下。
我有一个从后面获得的 SimplifiedBill
列表,当我单击其中一个时,我请求并从 api 中获得 Bill
并进入详细视图。
如果您想知道,我正在使用 Angular,并且我有一个 ListComponent
(或视图),其中我有我的 SimpleBill
objects ,当我点击其中一个时,我会转到 DetailComponent
,在那里我可以看到特定的 Bill
。当我从一个视图转到另一个视图时,我无法传输 object SimpleBill
,只能传输其 ID(或其他字段)。
不,我同意,从 SimplifiedBill 继承在概念上是不正确的。 一般来说,我认为谨慎使用继承是明智的。我很少看到它被正确使用。
相反,我会推荐一种组合方法:如果 Bill 包含 SimplifiedBill,那么我认为拥有一个具有详细信息属性的数据结构 Bill 是有意义的:
let bill = {
details: {...},
simplifiedBill: {...}
}
请注意,我在这里使用了一个简单的对象(当您使用 javascript 时,它可能也值得考虑),但它同样适用于基于 class 的方法。 不过,您可能想为简化的账单想一个不同的名称。也许像 "summary".
但总的来说,您想到这里可能不太适合的继承概念是件好事。
我倾向于认为你可能甚至不需要这里的关系;听起来 SimplifiedBill
class 更像是 Bill
class.
解决这个问题的一种方法是将两个 class 完全分开,并引入第三个 class,类似于 SimplifiedBillFactory
,需要 [=12] =] 并生成 SimplifiedBill
.
例如(伪代码,可能不是有效的打字稿!)
export class SimplifiedBillFactory
{
createSimplifiedBill(bill: Bill) : SimplifiedBill
{
return new SimplifiedBill{
billId=bill.Id,
date=bill.date,
finalPayment=bill.calculateFinalPayment()
};
}
}
这种方法的一个优点是,如果您需要扩充 SimplifiedBill
以包含更多详细信息(例如可能有一些聚合,例如订单项的总数等),可以在此处轻松完成 class。此外,它鼓励您将法案的实际行为保留在 Bill
class 本身中,并通过方法公开它们(例如 Bill
上的 calculateFinalPayment
方法)
您也可以只在 Bill
class 上使用工厂方法而不是单独的工厂 class,但我个人更愿意将其分开,例如,如果除了 Bill
class 之外,您稍后还需要使用其他 class 来创建您的 SimplifiedBill
实例。
有趣的问题,
继承是一种is-a
关系。当你在它们之间建立继承关系时,问问自己A是不是B。
- 第一个问题:什么是最简单的法案或法案至少应该有什么?答案也回答了
Bill
应该是什么。
由于SimpleBill
也是Bill
的一种,所以SimpleBill
的子集使得Bill
,Bill本身可以简单到只有一个billId(根据评论)。所以 Bill
将是:
interface Bill{
billId: string;
}
- 第二题:
VerboseBill
是SimpleBill
还是相反?,答案也回答了它们之间是否存在继承关系
奇怪的是SimpleBill
是VerboseBill
或者相反,所以他们没有继承关系;
以后你可能还有其他的账单,比如AaaBill{taxes}
,BbbBill{services}
...,他们有继承关系吗?但他们都是 Bill
!
我的建议:
export interface SimpleBill extends Bill{
date: number;
finalPayment: number;
}
export interface VerboseBill extends Bill{
date: number;
finalPayment: number;
taxes:number;
services;...
userData;...
}
export namespace Bill{
export function simplify(bill:Bill): SimpleBill{
return {id: bill.id, date: bill.date, finalPayment: bill.finalPayment};
}
export function verbose(bill:Bill): VerboseBill{
if((bill as VerboseBill).taxes !==undefined){
return bill as VerboseBill;
}
return fetchVerboseBill(bill.id);
}
}
export namespace SimpleBill{
export const verbose = Bill.verbose
}
export namespace VerboseBill{
export const simplify = Bill.simplify
}