Is there a pattern for a more “natural” way of adding items to collections? [closed]

I think the most common way of adding something to a collection is to use some kind of Add method that a collection provides:

class Item {}    
var items = new List<Item>();
items.Add(new Item());

and there is actually nothing unusual about that.

I wonder however why don’t we do it this way:

var item = new Item();
item.AddTo(items);

it seems to be somehow more natural then the first method. This would have the andvantange that when the Item class has a property like Parent:

class Item 
{
    public object Parent { get; private set; }
} 

you can make the setter private. In this case of course you cannot use an extension method.

But perhaps I’m wrong and I’ve just never seen this pattern before because it’s so uncommon? Do you know whether there is any such pattern?

In C# an extension method would be useful for that

public static T AddTo(this T item, IList<T> list)
{
    list.Add(item);
    return item;
}

How about other languages? I guess in most of them the Item class had to provide a let’s call it ICollectionItem interface.


Update-1

I’ve been thinking about it a little bit more and this pattern would be really usefull for example if you don’t want an item to be added to multiple collections.

test ICollectable interface:

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);
}

and a sample implementation:

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
}

usage:

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);

14

No, item.AddTo(items) it is not more natural. I think you mix this up with the following:

t3chb0t.Add(item).To(items)

You are right in that items.Add(item) is not very near to the natural english language. But you also don’t hear item.AddTo(items) in natural english language, do you? Normally there is someone who supposed to add the item to the list. Be it when working at a supermarket or while cooking and adding ingredients.

In the case of programming languages, we made it so that a list does both: storing its items and being responsible for adding them to itself.

The problem with your approach is that an item has to be aware that a list exists. But an item could exist even if there were no lists at all, right? This shows that it should not be aware of lists. Lists should not occur in its code in any way at all.

Lists however don’t exist without items (at least they would be useless). Therefore its fine if they know about their items – at least in a generic form.

0

@valenterry is quite right about the problem of separation of concerns. Classes should know nothing about the various collections which might contain them. You would not want to have to change the item class each time you create a new kind of collection.

That said…

1. Not Java

Java is no help to you here, but some languages have more flexible, extensible syntax.

In Scala, items.add(item) looks like this:

  item :: items

Where :: is an operator which adds items to lists. That seems very much what you want. It is actually syntactic sugar for

  items.::(item)

where :: is a Scala list method which is effectively equivalent to Java’s list.add. So while it looks in the first version as if item is adding itself to items, in truth items is doing the adding. Both versions are valid Scala

This trick is done in two steps:

  1. In Scala, operators are really just methods. If you import Java lists into Scala, then items.add(item) can also be written items add item. In Scala, 1 + 2 is actually 1.+(2). In the version with spaces rather than dots and brackets, Scala sees the first object, looks for a method matching the next word and (if the method takes parameters) passes the next thing (or things) to that method.
  2. In Scala, operators which end in a colon are right-associative rather than left. So when Scala sees the method, it looks for the method owner on the right and feeds in the value on the left.

If you are not comfortable with lots of operators and want your addTo, Scala offers another option: implicit conversions. This requires two steps

  1. Create a wrapper class called, say, ListItem which takes an item in its constructor and has an addTo method which can add that item to a given list.
  2. Create a function which takes an item as a parameter and returns a ListItem containing that item. Mark it as implicit.

If implicit conversions are enabled and Scala sees

  item addTo items

or

  item.addTo(items)

and item does not have addTo, it will search the current scope for any implicit conversion functions. If any of the conversion functions returns a type which does have an addTo method, this happens:

  ListItem.(item).addTo(items)

Now, you may find the implicit conversions route more to your taste, but it adds danger, because code can do unexpected things if you are not clearly aware of all the implicit conversions in a given context. This is why this feature is no longer enabled by default in Scala. (However, while you can choose whether or not to enable it in your own code, you can do nothing about its status in other people’s libraries. Here be dragons).

The colon-terminated operators are uglier but do not pose a threat.

Both approaches preserve the principle of separation of concerns. You can make it look as if item knows about collection, but the work is actually done somewhere else. Any other language which wants to give you this feature should be at least as careful.

2. Java

In Java, where the syntax is not extensible by you, the best you can do is create some kind of wrapper/decorator class which knows about lists. In the domain where your items are placed in lists, you could wrap them in that. When they leave that domain, take them out. Maybe the visitor pattern is closest.

3. tl;dr

Scala, like some other languages, can help you with more natural syntax. Java can only offer you ugly, baroque patterns.

With your extension method you still have to call Add() so its not adding anything useful to your code. Unless your addto method did some other processing there’s no reason for it to exist. And writing code that has no functional purpose is bad for readability and maintainability.

If you leave it non generic the problems become even more apparent. You now have an item that needs to know about different kinds of collections it can be in. That violates the single responsibility principle. Not only is an item a holder for it’s data, it also manipulates collections. Which is why we leave the responsibility for adding items to collections up to the piece of code that is consuming both of them.

2

I think you are obsessing with the word “add”. Try looking for an alternative word instead, such as “collect”, which would give you a more English-friendly syntax with no change in pattern:

items.collect(item);

The above method is exactly the same as items.add(item);, with the only difference being different word choice, and flows very nicely and “naturally” in English.

Sometimes, merely re-naming variables, methods, classes, etc. will prevent the taxing re-designing of the pattern.

2

Although there is no such pattern for the general case (as explained by others), the context in which a similar pattern does have its merits is a bidirectional one-to-many association in ORM.

In this context you’d have two entities, let’s say Parent and Child. A parent can have many children, but each child belongs to one parent. If the application requires the association to be navigable from both ends (bidirectional), you would have a List<Child> children in the parent class and a Parent parent in the child class.

The association should always be reciprocal of course. ORM solutions typically enforce this on entities that they load. But when the application is manipulating an entity (either persisted or new), it has to enforce the same rules. In my experience, you’d most often find a Parent.addChild(child) method that invokes Child.setParent(parent), which is not for public use. In the latter you’d typically find the same checks as you have implemented in your example. The other route can however also be implemented: Child.addTo(parent) which calls Parent.addChild(child). Which route is best differs from situation to situation.

In Java, a typical collection doesn’t hold things–it holds references to things, or more accurately copies of references to things. Dot-member syntax, by contrast, is generally used to act upon the thing identified by a reference, rather than upon the reference itself.

While placing an apple in a bowl would alter some aspects of the apple (e.g. its location), placing a slip of paper that says “object #29521” into a bowl wouldn’t change the apple in any way even if it happens to be object #29521. Further, because collections hold copies of references, there’s no Java equivalent to placing a slip of paper saying “object #29521” into a bowl. Instead, one copies the number #29521 to a new slip of paper, and show (not give) that to the bowl, which will them make its own copy, leaving the original unaffected.

Indeed, since object references (the “slips of paper”) in Java can be passively observed, neither the references, nor the objects identified thereby, have any way of knowing what is being done with them. There are some kinds of collections which, rather than merely holding a bunch of references to objects that may know nothing of the collection’s existence, instead establish a bidirectional relationship with the objects encapsulated therein. With some such collections, it may make sense to ask a method to add itself to a collection (especially if an object is only capable of being in one such collection at a time). In general, though, most collections don’t fit that pattern, and may accept references to objects without any involvement whatsoever on the part of the objects identified by those references.

3

item.AddTo(items) is not used because it is passive. C.f. “The item is added to the list” and “the room is painted by the decorator”.

Passive constructions are fine, but, at least in English, we tend to prefer active constructions.

In OO programming, the pardigm gives prominence to actors, not those acted upon, so we have items.Add(item). The list is the thing doing something. It is the actor, so this is the more natural way.

6

Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa Dịch vụ tổ chức sự kiện 5 sao Thông tin về chúng tôi Dịch vụ sinh nhật bé trai Dịch vụ sinh nhật bé gái Sự kiện trọn gói Các tiết mục giải trí Dịch vụ bổ trợ Tiệc cưới sang trọng Dịch vụ khai trương Tư vấn tổ chức sự kiện Hình ảnh sự kiện Cập nhật tin tức Liên hệ ngay Thuê chú hề chuyên nghiệp Tiệc tất niên cho công ty Trang trí tiệc cuối năm Tiệc tất niên độc đáo Sinh nhật bé Hải Đăng Sinh nhật đáng yêu bé Khánh Vân Sinh nhật sang trọng Bích Ngân Tiệc sinh nhật bé Thanh Trang Dịch vụ ông già Noel Xiếc thú vui nhộn Biểu diễn xiếc quay đĩa Dịch vụ tổ chức tiệc uy tín Khám phá dịch vụ của chúng tôi Tiệc sinh nhật cho bé trai Trang trí tiệc cho bé gái Gói sự kiện chuyên nghiệp Chương trình giải trí hấp dẫn Dịch vụ hỗ trợ sự kiện Trang trí tiệc cưới đẹp Khởi đầu thành công với khai trương Chuyên gia tư vấn sự kiện Xem ảnh các sự kiện đẹp Tin mới về sự kiện Kết nối với đội ngũ chuyên gia Chú hề vui nhộn cho tiệc sinh nhật Ý tưởng tiệc cuối năm Tất niên độc đáo Trang trí tiệc hiện đại Tổ chức sinh nhật cho Hải Đăng Sinh nhật độc quyền Khánh Vân Phong cách tiệc Bích Ngân Trang trí tiệc bé Thanh Trang Thuê dịch vụ ông già Noel chuyên nghiệp Xem xiếc khỉ đặc sắc Xiếc quay đĩa thú vị
Trang chủ Giới thiệu Sinh nhật bé trai Sinh nhật bé gái Tổ chức sự kiện Biểu diễn giải trí Dịch vụ khác Trang trí tiệc cưới Tổ chức khai trương Tư vấn dịch vụ Thư viện ảnh Tin tức - sự kiện Liên hệ Chú hề sinh nhật Trang trí YEAR END PARTY công ty Trang trí tất niên cuối năm Trang trí tất niên xu hướng mới nhất Trang trí sinh nhật bé trai Hải Đăng Trang trí sinh nhật bé Khánh Vân Trang trí sinh nhật Bích Ngân Trang trí sinh nhật bé Thanh Trang Thuê ông già Noel phát quà Biểu diễn xiếc khỉ Xiếc quay đĩa
Thiết kế website Thiết kế website Thiết kế website Cách kháng tài khoản quảng cáo Mua bán Fanpage Facebook Dịch vụ SEO Tổ chức sinh nhật