【问题标题】:C# Processing same object with different "processors" a flyweight pattern?C#用不同的“处理器”处理相同的对象是一种轻量级模式?
【发布时间】:2013-08-07 21:05:26
【问题描述】:

我一直在对不同的设计模式进行大量研究,并试图确定正确的方法。

我正在开发一个图像上传 MVC 应用程序,它需要以几种不同的方式处理图像,例如创建缩略图和保存数据库记录。解决这个问题的最佳方法是通过享元模式吗?以此为例:

var image = new Image();    

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

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

我也有这个问题的第二部分。如果处理器有较小的相关“子处理器”怎么办?我脑海中的一个例子是书籍生成器。

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

这也是享元模式吗?我将如何处理那棵树的遍历?

编辑

我在下面问了这个问题,但我想在这里添加它:

我看到的所有关于复合模式的示例似乎都与值的处理有关,而享元模式似乎与对象状态的处理(或共享)有关。我只是读了太多的例子吗?将这些模式结合起来会是解决方案吗?

【问题讨论】:

  • 哟,老兄。我听说你喜欢事物里面的东西,所以我给你一个复合材料里面的复合材料,这样你就可以复合复合材料了! (en.wikipedia.org/wiki/Composite_pattern)
  • Would combining the patterns be the solution? 是的,这就是所谓的架构。模式本身并不能解决问题,它们只是解决问题的方法。
  • 是的,我明白了。不幸的是,我在一个学习模式被认为是浪费时间的环境中工作。我想问这个问题以确保我的头朝着正确的方向前进
  • I, unfortunately, work in an environment where studying patterns is considered a waste of time. 哈。我完全明白。唯一的“浪费时间”是大量时间浪费,因为代码没有被重构为任何有意义的架构,整个代码库不可避免地变成“只写”
  • 让一组顺序处理器就地处理您的数据更接近访问者模式。但是,以创建副作用为目的的处理(将缩略图保存到数据库等)不是访问者。您的示例具有责任链和命令模式的某些特性,但两者都不是。

标签: c# design-patterns tree flyweight-pattern


【解决方案1】:

我至少可以处理问题的第二部分。要扩展树(或复合树),请使用简单递归。

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

【讨论】:

  • 我看到的所有复合模式的例子似乎都与值的处理有关,而享元模式似乎与对象状态的处理(或共享)有关。我是不是看太多例子了?
  • Composite 用于构建树之类的东西(想想树视图或菜单项,其中的子项与其父项相同)。您使用递归来解开树/复合(查找:“深度优先搜索”)。享元用于缓存之类的东西,您可以在其中重复使用相同的东西,只是在不同的上下文中。例如,文本编辑器只加载一次字体的图像,然后在遇到特定字符代码时重复使用字形。在渲染文本时继续使用独立图像是没有意义的,因此您缓存图像并重用它们 - 享元。
  • 如果可以的话,还有一个问题。孩子成为不同的类型是否被认为是“可以接受的”?一个子类型?
  • 是的,当然。事实上,最初将这些模式编译在一起的 GoF 书强调针对“接口”而不是“实现”进行编程,因为它会使您的代码不那么依赖于所使用的特定实现。这样做的结果是您必须涉及某种子类化,但通常您会尝试(尽可能)针对基类/接口进行编程,而不是针对派生类(可以提供帮助)。
【解决方案2】:

您的描述可能有一些代表每个嵌套类的享元。但在这种情况下,这将是更多的实现细节。以我的经验,享元通常在架构级别或实现级别被调用,但很少作为设计元素。

考虑这个类 -

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

在您的多层应用程序中,此对象需要从源数据库传输到经理的 iPhone 以根据 blob 大小进行审批,然后再传输到会计系统进行计费。因此,您无需将整个内容传输到 iPhone 应用程序,而是替换为享元:

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

通过同时实现 IMyData 并使用接口而不是具体类型构建系统(你这样做了,对吗?!),然后你可以使用来自 iPhone 应用程序的 MyDataFlyweight 对象和 MyData 对象在系统的其余部分。您所要做的就是使用 blob 大小正确初始化 MyDataFlyweight

调用 iPhone 应用程序的架构将规定在 iPhone 应用程序中使用享元。

此外,考虑较新的Lazy&lt;T&gt; 类:

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

这是一个纯粹使用享元作为实现细节的示例。

【讨论】:

    猜你喜欢
    • 2011-07-02
    • 2016-10-06
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2015-11-05
    相关资源
    最近更新 更多