繁体   English   中英

这是一个糟糕的oop设计吗?

[英]Is this bad oop design?

我有一个名为Chicken的类,在Chicken中我有一些方法,所以在另一个我实例化并调用Chicken方法的类中,我可能会这样做:

Chicken chicken = new Chicken("Name","Description")


public void UpdateChicken(Chicken chicken)
{ 
   chicken.Update(chicken);
}

以上是罚款还是存在问题,如果是这样,是否更好地拥有另一个类,例如ChickenCalculations并执行以下操作:

public void UpdateChick(Chicken chicken)
{
    ChickenCalculations.Update(chicken);
}

这是一个实现:

Chicken chicken = new Chicken("Bob","Coolest Chicken", 4, 123, 5, 388, true, false, true);

Chicken anotherChicken = new Chicken()
anotherChicken.Update(chicken);
chicken.Update(chicken)

这是一个更实际的例子,而不是使用鸡:

public class AirlineBooking
{
    int BookingId {get;set;}
    string Name {get;set;}
    string Description {get;set;}
    decimal Price {get;set;}
    decimal Tax {get;set;}
    string seat {get;set;}
    bool IsActive {get;set;}
    bool IsCanceld {get;set;}


    public AirlineBooking(string name, string description, decimal price, 
                          decimal tax, string seat, bool isActive, bool isCanceled)
    {
        Name = name;
        Description = description;
        Price = price;
        Tax = tax;
        Seat = seat;
        IsActive = isActive;
        IsCanceled = isCanceled;
    }

    public Update(AirlineBooking airlineBooking, int id)
    {
          //Call stored proc here to update booking by id
    }

    public class BookingSystem
    {
       //Create new booking
       AirlineBooking booking = new AirlineBooking("ticket-1",
                                                   "desc",150.2,22.0,
                                                   "22A",true, false);

       //Change properties and update.
       booking.Name ="ticket-2";
       booking.Description = "desc2";
       booking.Price = 200.52;
       booking.Tax = 38.50;

       public void UpdateBooking(AirlineBooking booking, int id)
       {
            /* This is the meat of the question, should the passed in booking to
               update itself or should I have a Service Class , such as
               AirlineBookingOperations with an update method. */
            booking.Update(booking,id);
       }
    }
}

为什么UpdateChicken函数不是Chicken类的成员?

这样,您就不必传入Chicken对象的实例,而只需在现有实例上调用Update方法:

Chicken chicken = new Chicken("Name", "Description");
chicken.Update();

通常最好封装对该类内部特定类进行操作的所有方法,而不是将它们拆分为单独的“辅助”类。 让他们自己管理!

面向对象编程的整个想法是将对象视为能够对自己采取行动。

所以你应该只使用chicken.Update()来更新鸡。

我将以你的AirlineBooking课程为例,因为很多人似乎对Chicken例子感到困惑。

一些介绍:

单一职责原则规定,一个对象应该有一个责任,它应该只关心自己的事情narow与责任一致。 例如, TaxCalculator应该负责计算税收,而不是例如转换货币 - 这是CurrencyConverter的工作。

这通常是一个非常好的主意 ,因为它意味着您的应用程序被组织成代码块,每个代码都有一个单一的责任,使其更容易理解,更安全。 另一种方法是,一个类或模块应该只有一个改变的理由,例如“我们计算税收的方式已经改变”,或“我们转换货币的方式已经改变”。


您需要问自己的问题是:

  • AirlineBooking的责任是AirlineBooking
  • 更新航空公司预订部分责任吗?

例如,在这种情况下,我会说AirlineBooking的责任是“封装航空公司预订”,更新航空公司预订实际上是预订系统的责任,而不是AirlineBooking

另外,另一种思考方式是,如果我将Update方法放在AirlineBooking这意味着:

  • 如果预订系统更改为使用Web服务而不是存储过程,则AirlineBooking类需要更改。
  • 如果航空公司预订的封装发生变化(可能暂停预订,或者现在记录了航空公司的名称),那么AirlineBooking需要更改。

AirlineBooking现在有许多不同的原因需要改变,所以它也不应该对“更新”负责


简而言之,我可能会这样做:

public class AirlineBooking
{
    public int BookingId {get;set;}
    /* Other properties */
}

public class BookingSystem
{
    public void UpdateBooking(AirlineBooking booking, int id)
    {
        // Call your SP here.
    }
}

您应该问自己这些问题的原因是因为它取决于您的应用程序中使用的AirlineBooking

例如,如果AirlineBooking是“察觉”(即引用)预订系统,那么您可以添加“帮助”方法,如下所示:

public class AirlineBooking
{
    public void Update(int id)
    {
        this.bookingSystem.UpdateBooking(this, id);
    }
}

你为什么不给你的鸡类一个方法“更新(一些参数......)”? 然后,你可以通过实现一只鸡

Chicken chicken = new Chicken("Name", "descr");

并更新:

chicken.Update(myparameters..);

编辑

public class Chicken
{
  public Chicken(string name, string description)
  {
     this.Name = name;
     this.Description = description;
  }

  public string Name { get; set; }
  public string Description { get; set; }

  // Fill in all the other properties!

  public int EggsDroppedInLife { get; set; }
}

现在您可以通过以下方式使用您的鸡类:

Chicken chicken = new Chicken("Harry", "Nice chick");
chicken.NumberOfEggs = 123;
chicken.Description = "Oh no, it's actually not nice.";
// ... change all the properties as you want

对象应该封装功能。 应传递功能以使封装对象具有灵活性。

所以,如果你要保存鸡,你应该传递存储库功能。 如果你有鸡计算,并且它们很容易改变,那么它也应该被传入。

class Chicken
{
   IChickenCalculations ChickenCalculations;
   IChickenRepository ChickenRepository;
   Chicken(IChickenCalculations chickenCalculations, IChickenRepository chickenRepository)
   {
       ChickenCalculations = chickenCalculations;
       ChickenRepository = chickenRepository ;
   }

   Calculate()
   {
       ChickenCalculations.Calculate(this);
   }
   Update()
   {
       ChickenRepository.Update(this);
   }
}

请注意,在这个例子中,鸡如何能够自己进行计算并坚持自己,而不知道如何进行计算或坚持事物(毕竟,它只是一只鸡)。

虽然我意识到没有Chicken ,你的真实对象可能会有一个Update方法,对吗?

我认为你应该尝试在语言方面介绍除“更新”之外的其他内容。 没有办法真正理解更新的作用。 它只是更新鸡肉中的“数据”吗? 在那种情况下,有什么数据? 而且,你是否应该被允许像这样更新鸡的实例?

我宁愿看到类似的东西

chicken.CanFly = false;
if(chicken.CanFly)  // inherited from Bird :)
    ckicken.FlyTo(point);
else
    chicken.WalkTo(point);

这是OOP中一个非常有趣的练习: http//milano-xpug.pbworks.com/f/10080616-extreme-oop.pdf

对于多线程环境,像ChickenCalculations这样的单独类更适合。 除了chicken.Update()之外,当你需要执行一些其他步骤时,你可以使用ChickenCalculations类来完成。 因此,如果在Chicken上实例化和调用方法的多个类不必担心ChickenCalculations类正在处理的事情。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM