简体   繁体   中英

Abstraction and Proper Class Design

I'm not new to programming but am relatively new to OOP, so I have a design question. 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. Along with the FruitBasket class, I will also design an Apple class, an Orange class, and a Pear class. Whenever I instantiate an object of type FruitBasket , it will automatically instantiate these other classes in a has-a relationship.

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?
  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 ? A Pear and an Orange ? An Apple and a Pear ? 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?

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 . That way you can use the Object Initializer syntax to do exactly what you are talking about. You will need to change your FruitBasket class like so:

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:

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.

edit: You may also want to have your fruit inherit from the Fruit base class. 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:

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

You could initialize your FruitBasket as follows:

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

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)

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? 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.

The technical post webpages of this site follow the CC BY-SA 4.0 protocol. If you need to reprint, please indicate the site URL or the original address.Any question please contact:yoyou2525@163.com.

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