Отказ от ответственности: как заявил Габриэль C в своем ответе , идеальный дизайн должен соответствовать принципу единой ответственности. Ваш вопрос, хотя, если интерпретировать его в буквальном смысле, ограничен только двумя классами, которые должны содержать все бизнес-логики c для обработки яблочного бокса. Вот мое решение с этим конкретным c дизайном.
Класс Apple:
public class Apple
{
public enum AppleKind
{
RedDelicious,
GrannySmith,
Golden,
PinkLady
}
public AppleKind Kind { get; }
public Apple(AppleKind kind)
{
this.Kind = kind;
}
public Box Box { get; private set; }
public void MoveToBox(Box box, int position)
{
if (box == null) throw new ArgumentNullException(nameof(box));
int oldPosition = -1;
var oldBox = this.Box;
if (oldBox != null)
{
oldPosition = oldBox.GetApplePosition(this);
oldBox.RemoveApple(this);
}
var moved = false;
try
{
this.Box = box;
Box.SetApplePosition(this, position);
moved = true;
}
finally
{
if (!moved)
{
if (oldBox != null)
oldBox.AddApple(this, oldPosition);
else
this.Box = null;
}
}
}
public void MoveToHand()
{
this.Box = null;
}
}
Класс коробки:
public class Box
{
private Apple[] _apples;
public IEnumerable<Apple> Apples
{
get
{
return _apples.Clone() as Apple[];
}
}
public Box(int maxPositions)
{
_apples = new Apple[maxPositions];
}
public void RemoveApple(Apple apple)
{
var position = GetApplePosition(apple);
if (position > -1)
{
_apples[position] = null;
apple.MoveToHand();
}
}
public int GetApplePosition(Apple apple)
{
return Array.IndexOf(_apples, apple);
}
public void SetApplePosition(Apple apple, int position)
{
// if apple is already in position, do nothing
if (object.ReferenceEquals(apple, _apples[position])) return;
_apples[position] = apple;
}
public void AddApple(Apple apple, int position)
{
if (_apples[position] != null) throw new ArgumentException("Compartment already occupied", nameof(position));
if (apple == null) throw new ArgumentNullException(nameof(apple));
if (position < 0 || position > _apples.Length - 1) throw new IndexOutOfRangeException("Cannot add apple outside compartments");
apple.MoveToBox(this, position);
}
}
Обратите внимание, что свойство Box.Apples возвращает клон нижележащего массива, предотвращая нарушение клиентским кодом отношения Apple-Box путем манипулирования элементами массива. Apple.Box имеет собственный установщик по той же причине.
Клонировать полный код, включая тесты, по адресу: https://github.com/cvalerio/TossAnAppleToYourWitcher