C# Processing same object with different "processors" a flyweight pattern?

1.7k views Asked by At

I've been doing a lot of research on different design patterns and I'm trying to determine the correct way of doing this.

I have an image uploading MVC app that I'm developing which needs to process the image in several different ways, such as create a thumbnail and save a database record. Would the best way to approach this be via a flyweight pattern? Using this as an example:

var image = new Image();    

List<IProcessors> processors = processorFactory.GetProcessors(ImageType.Jpeg);

foreach(IProcessor processor in processors)
{
    processor.process(image);
}

I have second part to this question as well. What if the processor has smaller related "sub-processors"? An example that I have in my head would be a book generator.

I have a book generator 
     that has page generators
          that has paragraph generators
               that has sentence generators

Would this be a flyweight pattern as well? How would I handle the traversal of that tree?

EDIT

I asked this question below but I wanted to add it here:

All the examples that I've see of the composite pattern seems to relate to handling of values while the flyweight pattern seems to deal with processing (or sharing) of an object's state. Am I just reading into the examples too much? Would combining the patterns be the solution?

2

There are 2 answers

4
sircodesalot On BEST ANSWER

I can at least handle the second part of the question. To expand a tree (or a composite), use simple recursion.

void Recursion(TreeItem parent) 
{
    // First call the same function for all the children.
    // This will take us all the way to the bottom of the tree.
    // The foreach loop won't execute when we're at the bottom.
    foreach (TreeItem child in parent.Children) 
    {
         Recursion(child);
    }
    
    // When there are no more children (since we're at the bottom)
    // then finally perform the task you want. This will slowly work
    // it's way up the entire tree from bottom most items to the top.
    Console.WriteLine(parent.Name);
}
0
Keith Payne On

What your describing could have some flyweights representing each of those nested classes. But in this case that would be more of an implementation detail. In my experience, flyweights are usually called for at the architectural level or implementation level but rarely as an element of design.

Consider this class -

public interface IMyData {
    IdType MyId { get; }
    byte[] BlobData { get; }
    long SizeOfBlob { get; }
}
public class MyData : IMyData {
    public IdType MyId { get; private set; }
    public byte[] BlobData { get; set; }
    public long SizeOfBlob { get { return BlobData.LongLength; } }
    }
}

In your multi-tiered application, this object needs to travel from the source database, to a manager's IPhone for approval based on the blob size, and then to an accounting system for billing. So instead of transporting the whole thing to the IPhone App, you substitute the flyweight:

public class MyDataFlyWeight : IMyData {
    public MyDataFlyWeight(IdType myId, long blobSize){
        MyId = myId;
        BlobSize = blobSize;
    }
    public IdType MyId { get; set; }
    public byte[] MutableBlobData { get { 
            throw new NotImplmentedException();
            }
        }
    public long BlobSize { get; private set; }
    }
}

By having both implement IMyData and by building the system with the interface and not the concrete type (you did this, right?!), then you could use MyDataFlyweight objects from the IPhone App and MyData objects in the rest of the system. All you have to do is properly initialize MyDataFlyweight with the blob size.

The architecture which calls for an IPhone App would dictate that a flyweight is used within the IPhone App.

In addition, consider the newer Lazy<T> class:

public class MyData : IMyData {
    public IdType MyId { get; private set; }

    private Lazy<byte[]> _blob = new Lazy<byte[]>(() => 
                                 StaticBlobService.GetBlob(MyId));
    public byte[] BlobData { get { return _blob.Value; } }
    public long SizeOfBlob { get { return BlobData.LongLength; } }
    }
}

This is an example of using the flyweight purely as an implementation detail.