我有来自多个组织(警察,消防,办公室)的数据,这些组织需要以不同格式输出。
为实现这一目标,我定义了以下内容(这有点简化):
交易类 -
警察课
火派
Office Class
正如您所看到的,警察,消防和办公室课程不共享任何共同点,主要用作数据承载实体。我打算使用Factory返回一个适当的泛型(不是C#泛型)Transaction对象与数据(事务对象中包含 Police,Fire或Office 数据),然后将返回的对象传递给策略模式,用于确定每个人需要的文件格式(CSV,Excel或XML;在配置文件中指定)。
我的问题在于Transaction对象的定义。
“3.”中的班级是什么类型Transaction类需要是什么?每个组织的数据不同,没有共同的成员,我无法为所有人定义公共类。
整体设计是否合适?我应该考虑哪些其他设计?
基于彼得的评论如下: 我认为使用泛型可能会有效,但我遇到了一个问题。我想使用工厂返回请求的对象,使用GetTransactionObject,如下所示。什么应该是GetTransactionObject的返回类型来容纳这个。
类TransactionFactory {
Dictionary<string, Type> typeClassLookup;
public TransactionFactory()
{
typeClassLookup = new Dictionary<string, Type>();
typeClassLookup.Add("Police", typeof(PoliceData));
typeClassLookup.Add("Fire", typeof(FireData));
}
Transaction<????> GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
答案 0 :(得分:2)
如果类型真的没有任何共同点,那么您不需要明确的基类。 System.Object
就足够了,就像许多其他泛型类型一样(即任何缺少约束的泛型类型)。
换句话说,您可以声明为:
class Transaction<T>
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { /* something goes here */ }
}
就个人而言,我会避免添加“部门类型”成员。毕竟,这是从类型参数T
隐含的。但是如果你愿意,你可以轻松地将其添加到上面。
如果您发现这些类型确实存在共同点,那么您的Transaction<T>
类型需要做的不仅仅是保留其中一种类型的实例(这是它可以做到的所有事情)约束),然后您将能够将该共性放入接口或基类(取决于特定需要),并在Transaction<T>
类的约束中指定。
请注意,您不清楚GenerateOutput()
要做什么,或者它应该如何运作。但假设您希望输出特定于每个Entity
值,在我看来, 是您的“共同点”。即,根本不是Transaction<T>
类需要实现该方法,而是每个实体类型。在这种情况下,你有这样的事情:
interface IDepartmentEntity
{
void GenerateOutput();
}
class Office : IDepartmentEntity
{
public void GenerateOutput() { /* department-specific logic here */ }
}
// etc.
然后你可以声明:
class Transaction<T> where T : IDepartmentEntity
{
public bool Success { get; private set; }
public T Entity { get; private set; }
public Transaction(bool success, T entity)
{
Success = success;
Entity = entity;
}
public void GenerateOutput() { Entity.GenerateOutput(); }
}
修改强>
Per Prasant的后续编辑,请求GetTransactionObject()
的建议......
执行此操作的正确方法取决于调用者和上下文,问题中未提供详细信息。恕我直言,最佳场景是调用者知道类型的地方。这样可以使用泛型的全部功能。
例如:
class TransactionFactory
{
public Transaction<T> GetTransactionObject<T>()
where T : IDepartmentEntity, new()
{
return new Transaction<T>()
{
Data = new T(),
params = null
}
}
}
然后你这样打电话:
Transaction<FireData> transaction = factory.GetTransactionObject<FireData>();
调用者当然已经知道它正在创建的类型,然后可以填写transaction.Data
对象的相应属性。
如果无法实现这种方法,那么您需要Transaction<T>
本身拥有基类或实现接口。请注意,在我的原始示例中,IDepartmentEntity
接口只有一个方法,它与GenerateOutput()
类中的Transaction
方法相同。
所以,也许,该接口实际上是关于生成输出而不是数据实体。将其称为IDepartmentEntity
,而不是IOutputGenerator
。
在这种情况下,您可能会遇到以下情况:
class Transaction<T> : IOutputGenerator
{
// all as before
}
class TransactionFactory
{
public IOutputGenerator GetTransactionObject(string org)
{
if( typeClassLookup.TryGetValue(org, out typeValue))
{
switch (typeValue.ToString())
{
case "policeData":
transactionObject = new Transaction<PoliceData>() { Data = new PoliceData(), params = null};
case "FireData":
transactionObject = new Transaction<FireData>() {Data = new FireData(), params = null};
}
}
return transactionObject;
}
}
这是一个较差的解决方案,因为这意味着调用者只能直接访问IOutputGenerator
功能。其他任何事情都需要做一些类型检查和特殊情况代码,这些都应该尽可能地避免。
注意:如果Transaction
类型有其他成员,就像GenerateOutput()
方法一样,独立于此处包含的类型T
,并且哪些会对那些不喜欢的用户有用知道T
,然后上面的一个可能的变化是不重用用于特定部门数据类型的接口,而是声明Transaction<T>
的基类,当然命名为{{1} },包含与Transaction
无关的所有成员。然后返回值可以是T
。
答案 1 :(得分:0)
- 该课程的类型是什么?#34; 3。&#34; Transaction类需要是什么?
醇>
要将您的部门类与各种导出类型分离,我建议您使部门类实现一个通用接口。像这样:
public interface Exportable {
// return a list of attribute names, values, and types to export
IList<Tuple<String, String, Type>> GetAttributes();
}
例如:
public class Police : Exportable {
public IList<Tuple<String, String, Type>> GetAttributes() {
// return list size 3 - attribute info for Age, VehicleNumber, Supervisor
}
}
- 整体设计是否合适?我应该考虑哪些其他设计?
醇>
Transaction
班级设计似乎不适合这个问题。
考虑一个Export
类,每个导出类型都有一个方法,每个方法接收从Exportable
接口方法返回的属性。基本概要:
public static class Export {
public static boolean CSV(IList<Tuple<String, String, Type>> attributes) {
// export attributes to CSV, return whether succeeded
}
public static boolean Excel(IList<Tuple<String, String, Type>> attributes) {
// export attributes to Excel, return whether succeeded
}
// same thing for XML
}