0

请忽略语言语法,我想在这里只讨论 OOPS。


我将在这里展示 2 个代码片段,每个都是 Composition 的示例(如果我没记错的话)。

问题陈述:我有一个对象,它保存系统中实体的统计信息。让这些统计数据为:

  1. 姓名
  2. 薪水

*这些字段可以是任何东西,我只是以这些为例。所以请不要考虑什么领域是必要的。假设这三个都是必要的。

我创建了一个对应于这些字段的类:

public class Stats{
field Name;
field LatsName;
field Salary;
}

现在我遇到了一种情况,我想要跨时间段获取有关一个人的信息。让我们看看工作流系统中的某个点需要在所有三个阶段向它呈现一个人的信息

  1. 他小时候。
  2. 当他年轻的时候。
  3. 当他退休时。

这里要注意的是,name不会lastName改变,只有薪水可能会改变。正因为如此,我认为我也许可以创建一个可以使用现有对象“统计”的类。

我将提出两种解决方案,请建议哪一种更好以及为什么

代码示例 1

public class CompositeStats{
  //Adding three more properties and hinding the one already existing.
  private objStats= new Stats();
  public field FirstName{
    get{return objStats.Name;}
    set{objStats.Name=value;}
  }
  public field LastName{
    get{return objStats.LastName;}
    set{objStats.LastName=value;}
  }

  public field SalaryChild{get;set;}
  public field SalaryYoung{get;set;}
  public field SalaryRetired{get;set;}
}

在上面的示例代码中,我没有暴露原始的工资字段,而是为每个时间跨度创建了 3 个新字段。

代码示例 2

public class CompositeStats{
  private objStatsChild= new Stats();
  private objStatsYoung= new Stats();
  private objStatsRetired= new Stats();

  public field FirstName{
    get{return objStatsChild.Name;}
    set{objStatsChild.Name=value;}
  }

  public field LastName{
    get{return objStatsChild.LastName;}
    set{objStatsChild.LastName=value;}
  }

  public field SalaryChild{
    get{return objStatsChild.Salary;}
    set{objStatsChild.Salary=value;}
  }

  public field SalaryYoung{
    get{return objStatsYoung.LastName;}
    set{objStatsYoung.LastName=value;}
  }

  public field SalaryRetired{
    get{return objStatsRetired.LastName;}
    set{objStatsRetired.LastName=value;}
  }

}
4

6 回答 6

2

我认为这样的事情会更好。它允许您在不更改对象模型的情况下创建新的生命阶段。

此外,如果一个人尚未达到某个阶段,则不会为其存储任何信息。名为“CurrentStage”的属性可以选择列表中的最新阶段。

public class Stage{
  object BeginStage;  // Probably a DateTime or similar class.
  object EndStage;    // Probably a DateTime or similar class.
  object Salary;
}

public class Stats{
  object Name;
  object LastName;
  IEnumerable<Stage> Stages;
}

您也可以使用这种变体。

public enum Stage {
  Child,
  Young,
  Retired,
}

public class StageSalary {
  Stage Stage;
  object Salary;
}

public class Stats{
  object Name;
  object LastName;
  List<StageInfo> Stages;
}
于 2009-07-23T15:02:59.860 回答
1

让我们考虑另一种用法:

var dictStages = new Dictionary<Stage,double>();

在这里,Stage 是一个枚举:Child, Adult, Retired

在您的班级中添加属性

CurrentStage - 这将反映 dictStage
CurrentSalary的最新阶段- 这将反映 CurrentStage 的薪水。

虽然,您可能希望公开一些可以为特定阶段返回 Salary 的方法。

于 2009-07-23T14:56:37.577 回答
1

我认为很明显第一个是更好的选择。

原因: 1、性能:

 private objStatsChild= new Stats();
private objStatsYoung= new Stats(); 
private objStatsRetired= new Stats();

当您实际上只需要其中一个实例的值时,为什么要创建三个实例。

  1. 糟糕的设计。您正在创建“Stats”的三个实例,并在返回名称时选择其中一个(随机,至少没有逻辑来选择其中一个)。

3.如果您只想在统计信息中隐藏“Salary”,那么它更像是继承的情况,将“Salary”从父类中删除。

于 2009-07-23T14:57:12.273 回答
1

查看名为“Facade”的设计模式,它允许您拥有从多个接口继承的单个类结构,并允许数据仅表示您将它们分类为的结构..即隐藏/忽略“子”字段仅用于“退休”等。

于 2009-07-23T15:03:23.400 回答
0

我会将您的代码重构为如下所示:

class Person {
   field Name;
   field LastName;
}

enum PersonAge {
   Child, Young, Retired
}

class Stage {
   public PersonAge Age { get; set; }
   field Salary;
}

class PersonStats {
   public Person Person { get; set; }
   public IList<Stage> Stages { get; set; }
}

是否有意义?

于 2009-07-23T15:04:49.577 回答
0

“经典”“IsA”、“HasA”思维将始终帮助您朝着正确的方向前进:

一个“Person”“HasA”“Collection of Data”,这些信息来自他的人生阶段。今天你说“三个”阶段,但当然你永远不会设计到对问题的如此有限的看法......对吗?

所以你有了

class Person {
  [vector or list or your favorite collection type] Data;
  Name;
  LastName;
};

您询问有关“HasA”对 Person 的引用的快照,以及您希望在快照中包含哪条数据的说明符:

class PersonInfoSnapshot {
  [reference to] Person;
  /* "reference to Person.Data" could mean anything that allows retrieval of the data that you need */
  [reference to] Person.Data;
};

特定类型、可见性等的详细信息留作练习。

于 2009-07-23T17:06:46.650 回答