这是糟糕的 oop 设计吗?

发布于 2024-10-31 02:34:39 字数 2246 浏览 2 评论 0原文

我有一个名为 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)

这是一个更实际的例子,而不是使用 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);
       }
    }
}

I have class called Chicken and in Chicken I have some methods,
so in another class where I instantiate and call methods on Chicken, I might do something like this:

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


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

Is the above fine or does it present problems, if so, is it better to have another class, such as ChickenCalculations and do something like:

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

Here is an implementation:

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

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

Here is a more practical example instead of using a 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);
       }
    }
}

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

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

发布评论

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

评论(7

药祭#氼 2024-11-07 02:34:39

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

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

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

通常最好将在特定类上操作的所有方法封装在内部 该类,而不是将它们分成一个单独的“帮助”类。让他们鸡自己管理吧!

Why isn't the UpdateChicken function a member of the Chicken class?

That way, you wouldn't have to pass in an instance of a Chicken object, but rather just call the Update method on an existing instance:

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

It's generally best to encapsulate all the methods that operate on a particular class inside of that class, rather than splitting them up into a separate "helper" class. Let them chickens manage themselves!

我的影子我的梦 2024-11-07 02:34:39

面向对象编程的整个思想是将对象视为能够对自身进行操作的对象。

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

The whole idea of Object Oriented Programing is to think of objects as able to act upon themselves.

So you should just use chicken.Update() to update a chicken.

淡淡绿茶香 2024-11-07 02:34:39

我将使用您的 AirlineBooking 类作为示例,因为很多人似乎对 Chicken 示例感到困惑。

一些介绍:

单一责任原则指出一个对象应该有一个单一责任,并且它应该只关注与该责任狭隘一致的事情。例如,TaxCalculator 应该负责计算税收,而不是例如转换货币 - 这是 CurrencyConverter 的工作。

这通常是一个非常好的主意,因为这意味着您的应用程序被构造成代码块,每个代码块都有一个职责,使其更容易理解并且更安全地进行更改。另一种表达方式是,类或模块应该有一个且仅有一个更改原因,例如“我们计算税收的方式已更改”或“我们转换货币的方式已更改”。


您需要问自己的问题是:

  • 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);
    }
}

I'm going to use your AirlineBooking class as an example because a lot of people seem to have confused themselves over the Chicken example.

Some introduction:

The Single responsibility principle states that an object should have a single responsibility and that it should only concern itself with things narow aligned with that responsibility. For example a TaxCalculator should only be responsible for calculating tax and not, for example, with converting currency - this is the job of the CurrencyConverter.

This is often a really good idea, as it means that your application is structured into chunks of code, each one with a single responsibility making it easier to understand and safer to change. Another way of putting this is that a class or module should have one and only one reason to change, for example "The way we calculate tax has changed", or "The way we convert currency has changed".


The questions you need to ask yourself are:

  • What is the responsibility of AirlineBooking?
  • Is updating an airline booking part of that responsibility?

For example in this case I would say that the responsibility of AirlineBooking is "Encapsulating an airline booking", and that updating an airline booking is in fact the responsibility of the booking system, not AirlineBooking.

Altertnaively, another way of thinking about this is that if I put the Update method on AirlineBooking this would mean that:

  • If the booking system changes to use a web service rather than a stored procedure then the AirlineBooking class needs to change.
  • If the encapsulation of an airline booking changes (maybe it is possible to suspend a booking, or the name of the airline is now recorded) then AirlineBooking needs to change.

I.e. AirlineBooking now has many different reasons to change and so it shouldn't also be responsible for "Updating"


In short, I'd probably do this:

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

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

The reason why you should ask yourself these questions is because it does depends on what AirlineBooking is used for in your application.

For example, if AirlineBooking is "aware" (i.e. has a reference to) the booking system then you could add a "helper" method, like this:

public class AirlineBooking
{
    public void Update(int id)
    {
        this.bookingSystem.UpdateBooking(this, id);
    }
}
む无字情书 2024-11-07 02:34:39

为什么不给 Chicken 类一个方法“Update(一些参数...)”?然后,您可以通过以下方式实例化鸡

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

Why don't you give your Chicken class a method "Update(some parameters...)"? Then, you can just instanciate a chicken by

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

and update by:

chicken.Update(myparameters..);

EDIT

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; }
}

And now you can use your chicken class the following way:

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
再见回来 2024-11-07 02:34:39

对象应该封装功能。应传入功能以赋予封装对象灵活性。

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

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

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

请注意,在这个示例中,鸡如何能够对自身执行计算并保存自己,而无需了解如何执行计算或保存事物(毕竟,它只是一只鸡)。

Objects should encapsulate functionality. Functionality should be passed in to give the encapsulating object flexibility.

So, if you're saving the chicken, you should pass in the repository functionality. If you have chicken calculations, and they're prone to change, it should be passed in as well.

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

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

Note that how in this example the chicken is able to both perform calculations on itself and persist itself, without having any knowledge of how to perform calculations or persisting things (after all, it's only a chicken).

天冷不及心凉 2024-11-07 02:34:39

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

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

我宁愿看到这样的东西

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

While I realize there is no Chicken there might be an Update method on your real object, right?

I think you should try introduce something else than "update" in terms of language. There is no way to really understand what update does. Does it just update the "data" in the Chicken? In that case, what data? And also, should you be allowed to update an instance of Chicken like that?

I would rather see stuff like

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

Here is a pretty interesting exercise in OOP: http://milano-xpug.pbworks.com/f/10080616-extreme-oop.pdf

抚笙 2024-11-07 02:34:39

对于多线程环境,有一个像 ChickenCalculations 这样的单独的类更适合。当您需要执行除 Chicken.Update() 之外的其他步骤时,您可以使用 ChickenCalculations 类来执行此操作。因此,如果多个类在 Chicken 上实例化和调用方法,则不必担心 ChickenCalculations 类正在处理的相同问题。

For multithreaded environment, having a seperate class like ChickenCalculations suits better. When you need to perform few other steps besides what chicken.Update() does, you can do that with ChickenCalculations class. So if multiple classes that instantiate and call methods on Chicken does not have to worry about the same things that ChickenCalculations class is taking care of.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文