I was trying to solve a specific problem that, in facts, is an example of a more general issue. Let' say that we have a couple of objects where one object depends on the other:

Bitmap AnImage;   // Several instances of this object are possible: an image is loaded; then is discarded; then a new image is loaded, and so on.

Public class PixelSelection    
{
     string GenericAttribute;
      int X;
      int Y;

     public PixelSelection(string myAttribute, int x, int y)
     {
          GenericAttribute = myAttribute;
          X = x;
          Y = y;
     }
}

The second object:

  1. is created this way: new PixelSelection("Whatever", AnImage.Width, AnImage.height) so it depends on the AnImage object;
  2. it exposes events that the main application could subscribe to.

Only a single instance of each class is required and both objects are created on demand by the user: you cannot use PixelSelection without a Bitmap instance but the need for the instance arises when the user needs to interact with the PixelSelection object.

The issue I am dealing with is how to keep in sync PixelSelection with the Bitmap; these are the possible scenarios I am considering:

  1. Declare the PixelSelection as property of the main form and then instantiate it each time a new bitmap is created. This requires a new event registration each time and makes the code prone to errors because each time a new Bitmap creation is required developers need to remember to instantiate a new PixelSelection object referred in a different code section.
  2. Instantiate the PixelSelection object at start, using the same object for all the Bitmap instances, updating its attributes X and Y only where it is really used in the code. This requires a new constructor without the x and y parameters because no Bitmap is available AND code to manage inconsistencies in the PixelSelection use when trying to perform actions on an instance without proper initialization.
  3. Use a wrapper object that has the Bitmap and the PixelSelection object as properties used only to force proper creation or update od the PixelSelection object when a Bitmap is assigned to. This sounds quite unnatural (or dirty) to me because this wrapper does not fit in the solution domain model, it is only a workaround to solve a very specific issue.
  4. Create a class derived from Bitmap having PixelSelection as property, managing its lifecycle in the obvious way. This leads possibly to super-fat classes that would be filled with a bunch of objects that are there not to model something but only to address object lifecycle needs and usage patterns.

The four tentative scenarios I have drafted are very different in abstraction and try to use different toolsets; worse, i feel that they could give evidence of an insufficient understanding of the OO model by me, showing confusion about object lifecycle issues and object orienting modeling. Could please someone help me to identify what is the best way to solve the problem an why, in terms of best practices, that solution is the proper answer? Thanks.

有帮助吗?

解决方案 3

I have found a solution that works for me. I understood that the real requirement is to have a single code section where I can perform any action required to keep in sync the two objects without creating unnecessary dependencies; the answer is: events. The solution for me has been to create a class (a singleton) where a method has the complete responsibility to load the picture in its PictureBox control; the class has a method to perform the update that fires an event:

/*
 * Load the picturebox in the control 
 */
        public   void UpdatePictureBox( Bitmap BitmapToBeLoaded, PictureBox CurrentPictureBox)
        {
            /*
             * If the Bitmap or the picturebox are null there is nothing to update: so exit keeping loaded the previous image
             */
            if (BitmapToBeLoaded == null) return ;

            CurrentPictureBox.Image = BitmapToBeLoaded;                // Assign the Bitmap to the control
            /*
             *  When loading, adapt the control size to the image size to avoid any distortion
             */
            CurrentPictureBox.Width = BitmapToBeLoaded.Width;          // Adapth width of the control size
            CurrentPictureBox.Height = BitmapToBeLoaded.Height;        // Adapth height of the control size    

            /*
             * Publish events defensively: Book .Net Components, pag. 108
             */
            try
            {
                if (null != ImageUpdated) ImageUpdated();    // Fire the event
            }
            catch
            {
            }
            return ;           
        }

This way all the action to performed after a new image is made available are performed subscribing the event, in a single section of code easily found and documented . I do not claim that this is the best solution; but what makes me happy is the fact that the design seems more clean.

其他提示

The issue I am dealing with is how to keep in sync PixelSelection with the Bitmap

Why don't you add a reference to Bitmap into PixelSelection?

public class PixelSelection    
{
     string GenericAttribute;
     int X;
     int Y;
     private readonly Bitmap bitmap;

     public PixelSelection(string myAttribute, int x, int y, Bitmap bitmap)
     {
          GenericAttribute = myAttribute;
          X = x;
          Y = y;
          this.bitmap = bitmap;
     }
}

It is impossible to give an absolute answer to a very abstract question, you are not really looking for a specific advice on a defined issue but rather a general guideline to something that might or might not be related to your question.

For this specific scenario I can't really see the "forced connection" between your PixelSelection-class and a Bitmap. Your PixelSelection needs a width and a height, but that's it, that doesn't require a Bitmap and it would be bad to add an extra dependency if it is not needed.

Also you state that you only need 1 instance of bitmap and 1 instance of PixelSelection. So create those as static elements/singletons and update them when necessary and all will be good?

In more general terms it is probably wise to go for solution 3 from a pure OO-design point of view. Unless of course it makes more sense in your specific scenario to use any other method. Or add a reference to bitmap into PixelSelection...

Without the complete picture and knowing for what type of limitations we cater for it is impossible to give a definitive answer.

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top