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:
FruitBasket
constructor, as shown, or is this bad practice? 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.