簡體   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