Я думаю, что наиболее распространенным способом добавления чего-либо в коллекцию является использование какого-либо Add
метода, который предоставляет коллекция:
class Item {}
var items = new List<Item>();
items.Add(new Item());
и в этом нет ничего необычного.
Интересно, однако, почему бы нам не сделать это таким образом:
var item = new Item();
item.AddTo(items);
это кажется более естественным, чем первый метод. Это будет иметь andvantange, что, когда у Item
класса есть свойство как Parent
:
class Item
{
public object Parent { get; private set; }
}
Вы можете сделать сеттер приватным. В этом случае, конечно, вы не можете использовать метод расширения.
Но, возможно, я ошибаюсь, и я просто никогда не видел этот шаблон раньше, потому что он настолько необычен? Знаете ли вы, есть ли такая картина?
В C#
методе расширения было бы полезно для этого
public static T AddTo(this T item, IList<T> list)
{
list.Add(item);
return item;
}
Как насчет других языков? Я полагаю, что в большинстве из них Item
класс должен был предоставить ICollectionItem
интерфейс , назовем его так .
Update-1
Я думал об этом немного больше, и этот шаблон будет очень полезен, например, если вы не хотите, чтобы элемент был добавлен в несколько коллекций.
тестовый ICollectable
интерфейс:
interface ICollectable<T>
{
// Gets a value indicating whether the item can be in multiple collections.
bool CanBeInMultipleCollections { get; }
// Gets a list of item's owners.
List<ICollection<T>> Owners { get; }
// Adds the item to a collection.
ICollectable<T> AddTo(ICollection<T> collection);
// Removes the item from a collection.
ICollectable<T> RemoveFrom(ICollection<T> collection);
// Checks if the item is in a collection.
bool IsIn(ICollection<T> collection);
}
и пример реализации:
class NodeList : List<NodeList>, ICollectable<NodeList>
{
#region ICollectable implementation.
List<ICollection<NodeList>> owners = new List<ICollection<NodeList>>();
public bool CanBeInMultipleCollections
{
get { return false; }
}
public ICollectable<NodeList> AddTo(ICollection<NodeList> collection)
{
if (IsIn(collection))
{
throw new InvalidOperationException("Item already added.");
}
if (!CanBeInMultipleCollections)
{
bool isInAnotherCollection = owners.Count > 0;
if (isInAnotherCollection)
{
throw new InvalidOperationException("Item is already in another collection.");
}
}
collection.Add(this);
owners.Add(collection);
return this;
}
public ICollectable<NodeList> RemoveFrom(ICollection<NodeList> collection)
{
owners.Remove(collection);
collection.Remove(this);
return this;
}
public List<ICollection<NodeList>> Owners
{
get { return owners; }
}
public bool IsIn(ICollection<NodeList> collection)
{
return collection.Contains(this);
}
#endregion
}
использование:
var rootNodeList1 = new NodeList();
var rootNodeList2 = new NodeList();
var subNodeList4 = new NodeList().AddTo(rootNodeList1);
// Let's move it to the other root node:
subNodeList4.RemoveFrom(rootNodeList1).AddTo(rootNodeList2);
// Let's try to add it to the first root node again...
// and it will throw an exception because it can be in only one collection at the same time.
subNodeList4.AddTo(rootNodeList1);
источник
item.AddTo(items)
Предположим, у вас есть язык без методов расширения: естественный или нет, для поддержки addTo каждому типу понадобится этот метод и предоставьте его для каждого типа коллекции, поддерживающей добавление. Это как лучший пример введения зависимостей между всем, что я когда-либо слышал: П - Я думаю, что ложная предпосылка здесь - попытка смоделировать некоторую программную абстракцию до «реальной» жизни. Это часто идет не так.add(item, collection)
, - это не хороший ОО-стиль.Ответы:
Нет,
item.AddTo(items)
это не более естественно. Я думаю, что вы смешали это со следующим:Вы правы в том, что
items.Add(item)
не очень близки к естественному английскому языку. Но вы также не слышитеitem.AddTo(items)
на естественном английском языке, не так ли? Обычно есть кто-то, кто должен добавить элемент в список. Будь то при работе в супермаркете или во время приготовления и добавления ингредиентов.В случае с языками программирования мы сделали так, чтобы список выполнял одновременно: хранение своих элементов и ответственность за их добавление к себе.
Проблема с вашим подходом состоит в том, что элемент должен знать, что список существует. Но предмет может существовать, даже если списков не было вообще, верно? Это показывает, что он не должен знать о списках. Списки вообще не должны встречаться в его коде.
Однако списки не существуют без элементов (по крайней мере, они будут бесполезны). Поэтому хорошо, если они знают о своих предметах - по крайней мере, в общей форме.
источник
@valenterry совершенно прав насчет проблемы разделения интересов. Классы не должны ничего знать о различных коллекциях, которые могут их содержать. Вам не нужно менять класс элементов каждый раз, когда вы создаете новую коллекцию.
Это сказал ...
1. Не Java
Java здесь вам не поможет, но некоторые языки имеют более гибкий, расширяемый синтаксис.
В Scala items.add (item) выглядит так:
Где :: это оператор, который добавляет элементы в списки. Это похоже на то, что вы хотите. Это на самом деле синтаксический сахар для
где :: - это метод списка Scala, который фактически эквивалентен списку Java list.add . Так что, хотя в первой версии это выглядит так, как будто элемент добавляет себя к элементам , в действительности элементы делают добавление. Обе версии действительны Scala
Этот трюк делается в два этапа:
Если вам неудобно работать с множеством операторов и вы хотите добавить свое приложение , Scala предлагает другой вариант: неявные преобразования. Это требует двух шагов
Если неявные преобразования включены и Scala видит
или
и элемент не имеет addTo , он будет искать в текущей области любые неявные функции преобразования. Если какие - либо из функций преобразования возвращает тип , который делает есть AddTo метод, это происходит:
Теперь вы можете найти путь неявных преобразований на ваш вкус, но это добавляет опасности, потому что код может делать неожиданные вещи, если вы не совсем понимаете все неявные преобразования в данном контексте. Вот почему эта функция больше не включена по умолчанию в Scala. (Тем не менее, хотя вы можете выбрать, включать его или нет в своем собственном коде, вы ничего не можете сделать с его статусом в библиотеках других людей. Здесь будут драконы).
Операторы с двоеточием заканчиваются ужаснее, но не представляют угрозы.
Оба подхода сохраняют принцип разделения интересов. Вы можете заставить его выглядеть так, как будто элемент знает о коллекции, но работа фактически выполняется где-то еще. Любой другой язык, который хочет дать вам эту функцию, должен быть как минимум осторожным.
2. Java
В Java, где синтаксис не расширяется вами, лучшее, что вы можете сделать, - это создать некоторый класс оболочки / декоратора, который знает о списках. В домене, где ваши элементы размещены в списках, вы можете включить их в это. Когда они покинут этот домен, уберите их. Может быть, шаблон посетителя ближе всего.
3. TL; Dr
Scala, как и некоторые другие языки, может помочь вам с более естественным синтаксисом. Java может предложить вам только уродливые узоры в стиле барокко.
источник
С вашим методом расширения вы все равно должны вызывать Add (), чтобы он не добавил ничего полезного в ваш код. Если ваш метод addto не выполнял какую-либо другую обработку, нет причин для его существования. А написание кода, не имеющего функционального назначения, плохо сказывается на удобстве чтения и обслуживания.
Если оставить его не общим, проблемы станут еще более очевидными. Теперь у вас есть предмет, который должен знать о различных видах коллекций, в которых он может находиться. Это нарушает принцип единой ответственности. Мало того, что предмет является держателем для его данных, он также манипулирует коллекциями. Вот почему мы оставляем ответственность за добавление элементов в коллекции до фрагмента кода, который потребляет их обоих.
источник
thing.giveTo(collection)
[и требованиеcollection
реализации интерфейса «acceptOwnership»] будет более целесообразной, чемcollection
включение метода, который захватит владение. Конечно ...Я думаю, что вы одержимы словом «добавить». Вместо этого попробуйте поискать альтернативное слово, такое как «собирать», которое даст вам более понятный для английского синтаксис без изменений в шаблоне:
Вышеупомянутый метод точно такой же, как
items.add(item);
и с единственным отличием, заключающимся в различном выборе слов, и течет очень красиво и «естественно» на английском.Иногда простое переименование переменных, методов, классов и т. Д. Будет препятствовать повторной разработке схемы налогообложения.
источник
collect
иногда используется в качестве имени для методов, которые превращают коллекцию элементов в какой-то особый результат (который также может быть коллекцией). Это соглашение было принято Java Steam API , что сделало использование имени в этом контексте чрезвычайно популярным. Я никогда не видел слово, использованное в контексте, который вы упоминаете в своем ответе. Я бы предпочел придерживатьсяadd
илиput
push
илиenqueue
. Дело не в конкретном названии примера, а в том, что другое имя может быть ближе к желанию ОП английской грамматики.Хотя в общем случае такого шаблона не существует (как объяснено другими), контекст, в котором подобный шаблон имеет свои достоинства, является двунаправленной ассоциацией «один ко многим» в ORM.
В этом контексте у вас будет две сущности, скажем,
Parent
иChild
. Родитель может иметь много детей, но каждый ребенок принадлежит одному родителю. Если приложение требует, чтобы ассоциация была навигационной с обоих концов (двунаправленной), у вас будетList<Child> children
родительский класс иParent parent
дочерний класс.Ассоциация всегда должна быть взаимной, конечно. Решения ORM обычно применяют это к объектам, которые они загружают. Но когда приложение манипулирует объектом (постоянным или новым), оно должно применять те же правила. По моему опыту, вы чаще всего найдете
Parent.addChild(child)
метод, который вызываетChild.setParent(parent)
, который не для публичного использования. В последнем случае вы обычно найдете те же проверки, что и в своем примере. Однако может быть реализован и другой маршрут:Child.addTo(parent)
какие звонкиParent.addChild(child)
. Какой маршрут лучше, зависит от ситуации.источник
В Java, типичный набор не держать вещи --Оно держат ссылки на вещи, точнее копию из ссылок на вещи. Напротив, синтаксический элемент-точка обычно используется для воздействия на объект, идентифицируемый ссылкой, а не на саму ссылку.
Если поместить яблоко в миску, это изменит некоторые аспекты яблока (например, его местонахождение), то, поместив листок бумаги с надписью «объект № 29521» в миску, это никак не изменит яблоко, даже если оно окажется Объект № 29521. Кроме того, поскольку в коллекциях хранятся копии ссылок, не существует Java-эквивалента для размещения куска бумаги с надписью «объект # 29521». Вместо этого кто-то копирует номер # 29521 на новый листок бумаги и показывает (а не дает) его чаше, которая сделает свою собственную копию, оставив оригинал без изменений.
Действительно, поскольку ссылки на объекты («листки бумаги») в Java можно пассивно наблюдать, ни ссылки, ни идентифицированные ими объекты не имеют никакого способа узнать, что с ними делается. Существуют некоторые виды коллекций, которые вместо того, чтобы просто хранить группу ссылок на объекты, которые могут ничего не знать о существовании коллекции, вместо этого устанавливают двунаправленную связь с объектами, инкапсулированными в ней. В некоторых таких коллекциях может иметь смысл попросить метод добавить себя в коллекцию (особенно если объект может находиться только в одной такой коллекции за раз). В целом, однако, большинство коллекций не соответствуют этому шаблону и могут принимать ссылки на объекты без какого-либо участия со стороны объектов, идентифицированных этими ссылками.
источник
item.AddTo(items)
не используется, потому что это пассивно. См. «Товар добавлен в список» и «Комната расписана декоратором».Пассивные конструкции хороши, но, по крайней мере на английском языке, мы предпочитаем активные конструкции.
В ОО-программировании парадигма отдает приоритет актерам, а не тем, на кого действовали, как мы
items.Add(item)
. Список - это то, что делает что-то. Это актер, так что это более естественный путь.источник
list.Add(item)
что элемент добавляется в список, или список добавляет элемент, или оitem.AddTo(list)
том, что элемент добавляется в список, или я добавляю элемент к списку или, как вы сказали, элемент добавлен в список - все они верны. Итак, вопрос в том, кто актер и почему? Элемент также является актером, и он хочет присоединиться к группе (списку), а группа не хочет иметь этот элемент ;-) элемент действует активно, чтобы быть в группе.Parent
свойство. По общему признанию, английский не является родным языком, но, насколько я знаю, желание не является пассивным, если я не хочу или он не хочет, чтобы я что-то делал ; -]List<T>
(по крайней мере, найденный вSystem.Collections.Generic
) не обновляетParent
свойства вообще. Как это может быть, если он должен быть общим? Обычно контейнер несет ответственность за добавление его содержимого.