简体   繁体   English

抽象和适当的类设计

[英]Abstraction and Proper Class Design

I'm not new to programming but am relatively new to OOP, so I have a design question. 我对编程并不陌生,但是对OOP相对较新,所以我有一个设计问题。 Actually, I have two questions wrapped up in the same problem. 实际上,在同一问题中我有两个问题。

For the sake of simplicity, let's say that I'm designing a FruitBasket class. 为了简单起见,假设我正在设计一个FruitBasket类。 Along with the FruitBasket class, I will also design an Apple class, an Orange class, and a Pear class. 除了FruitBasket类,我还将设计一个Apple类,一个Orange类和一个Pear类。 Whenever I instantiate an object of type FruitBasket , it will automatically instantiate these other classes in a has-a relationship. 每当我实例化FruitBasket类型的对象时,它将自动以has-a关系实例化这些其他类。

class Apple { //Apple implementation here }

class Orange { //Orange implementation here }

class Pear { //Pear implementation here }

class FruitBasket
{
     Apple _apple;
     Orange _orange;
     Pear _pear;

     public FruitBasket()
     {
          _apple = new Apple();
          _orange = new Orange();
          _pear = new Pear();
     }
}

class Program
{
     FruitBasket _fruitBasket;

     static void Main()
     {
          _fruitBasket = new FruitBasket();
     }
}

Ok, so here are my questions: 好的,这是我的问题:

  1. Is it acceptable to instantiate the various fruit objects in the FruitBasket constructor, as shown, or is this bad practice? 如图所示,在FruitBasket构造函数中实例化各种水果对象是否可以接受,还是这种不好的做法?
  2. This method seems fine if every single fruit basket is to contain all three fruits, however, what if I wish to instantiate fruit baskets that have only an Apple and an Orange ? 如果每个水果篮都包含全部三个水果,则此方法似乎很好,但是,如果我要实例化仅包含一个Apple和一个Orange水果篮该怎么办? A Pear and an Orange ? PearOrange An Apple and a Pear ? ApplePear Etc. What's the best approach to take? 等等,最好的方法是什么?

Would it be better to create a FruitBasket class that declares every fruit that might go into the basket and pass some argument that would tell the FruitBasket class which fruit classes to instantiate? 最好创建一个FruitBasket类来声明每个可能放入篮子的水果,并传递一些参数来告诉FruitBasket类实例化哪个水果类?

I don't really know what would work best, or if my thinking is even in the ballpark. 我真的不知道哪种方法最有效,或者即使我的想法还在讨论之列。

My suggestion would be to not create a default constructor for FruitBasket . 我的建议是不要为FruitBasket创建默认构造FruitBasket That way you can use the Object Initializer syntax to do exactly what you are talking about. 这样,您可以使用Object Initializer语法完全按照您的意思进行操作。 You will need to change your FruitBasket class like so: 您将需要像下面那样更改FruitBasket类:

public class FruitBasket
{
    public Apple apple { get; set; }
    public Orange orange { get; set; }
    public Pear pear { get; set; }
}

Then you will be able to create FruitBasket as follows: 然后,您将能够如下创建FruitBasket:

var fb1 = new FruitBasket { apple = new Apple() };
var fb2 = new FruitBasket { pear = new Pear() };
var fb3 = new FruitBasket { apple = new Apple() orange = new Orange() };

The Object Initializer syntax is quite powerful and if your class is really just a "property bag" it often is the easiest way. Object Initializer语法非常强大,如果您的类实际上只是一个“属性包”,那么它通常是最简单的方法。

edit: You may also want to have your fruit inherit from the Fruit base class. 编辑:您可能还想让您的水果继承自Fruit基类。 If you did that, you could use a combination of the Object Initialization syntax and the Collection Initialization syntax. 如果这样做,则可以结合使用对象初始化语法和集合初始化语法。 If you change your FruitBasket class to the following: 如果将FruitBasket类更改为以下内容:

public class FruitBasket
{
    public List<Fruit> fruit { get; set; }
}

You could initialize your FruitBasket as follows: 您可以按以下方式初始化FruitBasket

var fb3 = new FruitBasket{ fruit = new List<Fruit> { new Apple(), new Orange() } };
var fb4 = new FruitBasket{ fruit = new List<Fruit> { new Orange() } };
var fb5 = new FruitBasket{ fruit = new List<Fruit> { new Apple(), new Orange(), new Pear() } };

The fruitbasket must have that fruits or it can be empty sometimes? 水果篮必须有该水果,否则有时可能是空的? You can repeat any fruit? 你可以重复任何水果吗? If yes, you should study about inheritance and generics, where the you must have a base class Fruit and the basket could be just a generic List 如果是,则应该研究继承和泛型,在泛型中必须有一个基类Fruit,而篮子可能只是一个泛型List

abstract class Fruit
{

}
class Apple : Fruit
{
    //Apple implementation here
}

class Orange : Fruit
{
    //Orange implementation here
}

class Pear : Fruit
{
    //Pear implementation here
}

class Program
{

    static void Main()
    {
        List<Fruit> _fruitBasket = new List<Fruit>();

        _fruitBasket.Add(new Orange());
        _fruitBasket.Add(new Apple());
    }
}

Or you could do the following to have your basket as bountiful as you want: 或者,您可以执行以下操作以使篮子尽可能多地丰富:

abstract class Fruit {}
class Apple :Fruit  { //Apple implementation here }

class Orange : Fruit  { //Orange implementation here }

class Pear :Fruit  { //Pear implementation here }

class FruitBasket
{
     public List<Fruit> Contents {get;set;}

     public FruitBasket()
     {
       Contents = new List<Fruit>{new Apple(), new Orange(), new Pear()};
     }
}

Here is how I would approach the problem. 这是我将如何处理该问题的方法。 Instead of having a set of predefined fruits in the basket make it flexible by using a Collection of fruits. 而不是在篮中使用一组预定义的水果,而是使用“水果集合”使它变得灵活。 You won't be able to pass them into the constructor but add them via a method. 您将无法将它们传递到构造函数中,而是通过方法添加它们。 For that to work each fruit-class inherits the same interface (eg IFruit) 为此,每个水果类都继承相同的接口(例如IFruit)

So you have 所以你有了

class Apple : IFruit { ... }
class Orange : IFruit { ... }
etc

The upside is you can add as many types of fruit as you want and are not limited to the apples, oranges and pears. 好处是,您可以根据需要添加任意种类的水果,而不仅限于苹果,橙子和梨。

The Fruitbasket could look something like this 水果篮可能看起来像这样

public class FruitBasket {
    public FruitBasket() {
        _basket = new List<IFruit>();
    }

    public List<IFruit> Fruits {
        get { return _basket; }
    } 

    public AddFruit(IFruit fruit) {
        _basket.Add(fruit);
    }

    private readonly List<IFruit> _basket 
}

I would design it differenly. 我会设计不同。

class Fruit
{
}

class Apple : Fruit
{ //Apple implementation here }

class Orange : Fruit
{ //Orange implementation here }

class Pear : Fruit
{ //Pear implementation here }

class FruitBasket
{
     Ilist<Fruit> Fruits;

     public FruitBasket()
     {
          Fruits =new List<Fruit>();
     }

     public AddFruit(Fruit)
     {
     // Add Fruit implementation here
     }

      public RemoveFruit(Fruit)
     {
     // Remove Fruit implementation here
     }

}

class Program
{
     FruitBasket _fruitBasket;

     static void Main()
     {
         Fruit orange=new Orange(); 
         _fruitBasket = new FruitBasket();
         _fruitBasket.AddFruit(orange);
     }
}

Presumably, a FruitBasket can hold any type of fruit right? 大概一个FruitBasket可以容纳任何类型的水果,对吗? This sounds like a case for Polymorphism and Dependency Inversion. 这听起来像多态性和依赖反转的情况。

class FruitBasket {
  readonly List<Fruit> _fruits = new List<Fruit>();
  public FruitBasket(params Fruit[] fruits) {
    _fruits.AddRange(fruits);
  }
}
interface Fruit {}
class Apple : Fruit {}
class Orange : Fruit {}

In OOP you usually pass the dependencies in. 'Pre knowing' what the dependencies are is more procedural. 在OOP中,通常会传递依赖项。“预先了解”什么是依赖项是更具过程性的。

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

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