locked
How to write class that: only one object with particular (unique) field can be created! RRS feed

  • Question

  • I am making a library that it could be later use by various people.

    class WrapperMoveable
    {
     IMoveable moveable;
    
     public WrapperMoveable(IMoveable moveable)
     {
      this.moveable = moveable;
     }
    }
    

    The problem: how to edit WrapperMoveable class to be sure that exacly one object with particular IMoveable can exist. If someone is trying to create a wrapper object with some interface, and when the wrapper class with that interface already exist the mechanizm should return existing wrapper object.

    I have some solutions but please think by yourself about a problem firstly.

    Solutions:

    1. Create a static field in wrapper class that contains all created wrapper objects.

      class WrapperMoveable
      {
       IMoveable moveable;
      
       static List<WrapperMoveable> createdWrappers = new List<WrapperMoveable>();
      
       private WrapperMoveable(IMoveable moveable)
       {
        this.moveable = moveable;
       }
      
       public static WrapperMoveable CreateWrapper(IMoveable moveable)
       {
        if (createdWrappers.Any(e => e.moveable == moveable))
      return createdWrappers.First(e => e.moveable == moveable);
      WrapperMoveable newWrapper = new WrapperMoveable(moveable); createdWrappers.Add(newWrapper); return newWrapper; } }

      Problem with this method is that programmer can't normaly create object by using new keyword. So programmer has to know that object can be created only by static method. Also the garbridge collector will not release the object because the reference exist all time in createdWrappers.

    2. Creating a WrapperFactory class that creates wrapper classes. As in previous example proggramer has to know how to create wrapper object. In this solution by using factory class.

    3. By scanning all objects in memory of type WrapperMoveable and check if the object contains provided interface.

    What solution for this problem in your opinion is the best? Mayby you have your own better solution?


    Wednesday, July 6, 2011 10:49 PM

Answers

  • 1: This is reasonable, but I would recommend using a HashSet<T> instead of List<T> to store the objects.  You can also get around the garbage collection issue by storing a WeakReference instead of the object itself, and checking to see if there is a valid reference in the list.

    2: This is essentially the same as 1), with the addition of a separate class.  There is, from a theoretical standpoint, pretty much no difference.

    3: There is no way to easily "scan objects in memory" to see what type they are, so this is really not practical.  (It would also be incredibly slow).

     

    My preference would be to use method 1.  If you implement IDisposable, the Dispose method could remove the object from the queue.  YOu could, at debug, print an error in the finalizer for any object that never gets cleaned up.  If GC issues are a problem, using 1. with WeakReferences would eliminate the memory issue.

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by MaciejLisCK2 Wednesday, July 6, 2011 11:35 PM
    Wednesday, July 6, 2011 10:55 PM
  • Well, each call to the "new WrapperMoveable" will always create a new object.  So, no matter what you do, wrapper1.ReferenceEquals(wrapper3) will always be false.  However, you can override Equals and operator== to get the semantics above.

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by MaciejLisCK2 Wednesday, July 6, 2011 11:35 PM
    Wednesday, July 6, 2011 11:31 PM

All replies

  • 1: This is reasonable, but I would recommend using a HashSet<T> instead of List<T> to store the objects.  You can also get around the garbage collection issue by storing a WeakReference instead of the object itself, and checking to see if there is a valid reference in the list.

    2: This is essentially the same as 1), with the addition of a separate class.  There is, from a theoretical standpoint, pretty much no difference.

    3: There is no way to easily "scan objects in memory" to see what type they are, so this is really not practical.  (It would also be incredibly slow).

     

    My preference would be to use method 1.  If you implement IDisposable, the Dispose method could remove the object from the queue.  YOu could, at debug, print an error in the finalizer for any object that never gets cleaned up.  If GC issues are a problem, using 1. with WeakReferences would eliminate the memory issue.

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by MaciejLisCK2 Wednesday, July 6, 2011 11:35 PM
    Wednesday, July 6, 2011 10:55 PM
  • Thank you for a great answer!

    Solution 1 use Wrapper.CreateWrapper(); For various programmers that will use library, creating object with new keyword will be more natural.

    Do you think that exist any solution for this problem that can be provided with not resigning of creating a object by new keyword (as below)?

     

    class Moveable : IMoveable 
    {
    }
    
    
    Main()
    {
     Moveable a = new Moveable();
     Moveable b = new Moveable();
    
     WrapperMoveable wrapper1 = new WrapperMoveable(a);
     WrapperMoveable wrapper2 = new WrapperMoveable(b);
     WrapperMoveable wrapper3 = new WrapperMoveable(a);
    
     Console.Write(wrapper1==wrapper3);
    }
    

    true

     


    Wednesday, July 6, 2011 11:22 PM
  • Well, each call to the "new WrapperMoveable" will always create a new object.  So, no matter what you do, wrapper1.ReferenceEquals(wrapper3) will always be false.  However, you can override Equals and operator== to get the semantics above.

     

     


    Reed Copsey, Jr. - http://reedcopsey.com
    If a post answers your question, please click "Mark As Answer" on that post and "Mark as Helpful".
    • Marked as answer by MaciejLisCK2 Wednesday, July 6, 2011 11:35 PM
    Wednesday, July 6, 2011 11:31 PM
  • Shouldn't all constructors on the WrapperMoveable only be internal therefore enforcing all client libraries to use the factory pattern or static class defined above? Therefore, all instances of this class should work for equality checks (since it will be the same class), unless of course your factory isn't a Singleton or you need your WrapperMoveable to be serializable.
    Monday, July 11, 2011 1:43 PM
  • I agree with Reed Copsey. Reed you have provide very informative information.
    http://www.bankingresume.org/
    Wednesday, July 13, 2011 6:17 AM