有用的迷你图案(不是设计图案)

时间:2009-02-13 20:26:01

标签: c# .net design-patterns idioms

我最常用的迷你图案是:

VideoLookup = new ArrayList  { new ArrayList { buttonVideo1, "Video01.flv" },
                               new ArrayList { buttonVideo2, "Video02.flv" },
                               new ArrayList { buttonVideo3, "Video03.flv" }, 
                               new ArrayList { buttonVideo4, "Video04.flv" },
                               new ArrayList { buttonVideo4, "Video04.flv" }
                             };

这意味着,不是每个按钮都有一个case的switch语句,而是只需将单击的按钮与ArrayList中的每个项目进行比较。然后,当我找到匹配时,我会启动正确的文件(尽管第二部分“查找”的操作可能是委托或其他任何内容)。

主要的好处是我没有记住为每个switch语句添加所有正确代码的问题,我只是在查找ArrayList中添加一个新项。

(是的,我知道使用ArrayList不是最好的方法,但它是旧的代码。而且我知道每次循环遍历数组不如使用switch语句那么有效,但是这个代码没有紧密循环)

其他人是否有任何迷你图案可以节省时间/精力或使代码更具可读性? 他们不必只是与GUI相关

更新:不要复制此代码,我知道这很糟糕,但我没有意识到有多糟糕。请改用这样的东西。

Hashtable PlayerLookup = new Hashtable();
PlayerLookup.Add(buttonVideo1, "Video01.flv");
PlayerLookup.Add(buttonVideo2, "Video02.flv");
PlayerLookup.Add(buttonVideo3, "Video03.flv");
PlayerLookup.Add(buttonVideo4, "Video04.flv");

string fileName = PlayerLookup[currentButton].ToString();            

9 个答案:

答案 0 :(得分:5)

请请使用此版本。

VideoLookup = new Dictionary<Button, string> {
    { buttonVideo1, "Video01.flv" },
    { buttonVideo2, "Video02.flv" },
    { buttonVideo3, "Video03.flv" }, 
    { buttonVideo4, "Video04.flv" },
    { buttonVideo4, "Video04.flv" }
};

答案 1 :(得分:3)

你可以创建一个结构或对象,它有一个按钮引用和一个表示文件名的字符串,然后是这些东西的List。或者,你可以使用一个词典,让自己更容易。有很多方法可以改进。 :)

答案 2 :(得分:3)

关于开关的主题,我写了很多这样的东西:

public Object createSomething(String param)
{
    return s == null                          ? new NullObject() :
           s.equals("foo")                    ? new Foo() :
           s.equals("bar")                    ? new Bar() :
           s.equals("baz") || s.equals("car") ? new BazCar() :
                                                new Object();
}

我认为与常规switch语句相比,它看起来更具可读性,并且能够进行更复杂的比较。是的,它会慢一点,因为你需要比较每个条件,但99%的时间都无关紧要。

答案 3 :(得分:3)

在Java中,我有时会发现实现公共接口的私有内部类对于由紧耦合元素组成的对象非常有用。我已经在使用Allen Holub的Visual Proxy架构创建UI的背景下讨论过这个迷你模式(成语),但除此之外没有多少。据我所知,它没有名字。

例如,假设您有一个可以提供迭代器的Collection接口:

public interface Collection
{
  ...

  public Iterator iterate();
}

public interface Iterator
{
  public boolean hasNext();
  public Object next();
}

如果您有一个实现Collection的Stack,那么您可以将其Iterator实现为私有内部类:

public class Stack implements Collection
{
  ...

  public Iterator iterate()
  {
    return new IteratorImpl();
  }

  private class IteratorImpl implements Iterator
  {
    public boolean hasNext() { ... }
    public Object next() { ... }
  }
}

Stack.IteratorImpl可以完全访问Stack的所有私有方法和字段。同时,Stack.IteratorImpl对除Stack之外的所有人都是不可见的。

堆栈及其迭代器将倾向于紧密耦合。最糟糕的情况是,将Stack的Iterator实现为公共类可能会迫使您破坏Stack的封装。私有内部类可以让你避免这种情况。无论哪种方式,您都可以避免使用真正具有实现细节的内容来污染类层次结构。

答案 4 :(得分:2)

在我上一份工作中,我写了一篇由Andrei Alexandrescu和Petru Marginean(original article here)用C ++引入的Enforcements概念的C#版本。

这真的很酷,因为它可以让您在不中断流程的情况下将错误处理或条件检查与正常代码交织在一起 - 例如:


string text = Enforce.NotNull( myObj.SomeMethodThatGetsAString(), "method returned NULL" );

这将检查第一个参数是否为null,如果是,则抛出带有第二个参数的EnforcementException作为消息,否则返回第一个参数。还有重载采用字符串格式化参数,以及允许您指定不同异常类型的重载。

你可能会认为这种事情在C#中不太相关,因为运行时检查更好并且已经非常有用 - 但是这个习惯用法可以让你更接近源并提供更多信息,同时保持表达。

我使用相同的系统进行前置和后置条件检查。

我可能会写一个开源版本并从这里链接它。

答案 5 :(得分:1)

因为我快速生成代码(最后期限!截止日期!为什么我在stackoverflow.com上?截止日期!),我最终得到了这样的代码:

Button1.Click += (o,e) => { DoSomething(foo); };

这会在某些时候导致内存泄漏吗?我不确定!这可能值得一个问题。确认!期限!

答案 6 :(得分:0)

对于Windows表单,我经常使用Tag字段来放置一个伪命令字符串,这样我就可以为一组共享按钮设置一个事件处理程序。这对于几乎完全相同但参数化的按钮特别有效。

在你的第一个例子中,我将按钮的Tag设置为等于视频文件的名称 - 不需要查找。

对于具有某种形式的基于文本的命令处理器用于调度操作的应用程序,Tag是一个刚刚送入命令处理器的字符串。效果很好。

(顺便说一句:我看过用于迷你图案的“成语”一词......)

答案 7 :(得分:0)

我开始在C#中看到一个新的习惯用法是使用封闭参数来封装该方法需要运行的一些配置或设置。这样,您就可以控制代码必须在方法中运行的相对顺序。

这被称为Martin Fowler的嵌套闭包:http://www.martinfowler.com/dslwip/NestedClosure.html

答案 8 :(得分:0)

也许已经有了更好的方法(vbEx2005 / .Net2.0),但我发现有一类通用委托创建者接受一个带有一些参数的方法以及值这些参数中的全部或全部,或者除了一个之外的所有参数,并产生一个委托,当被调用时,它将使用指示的参数调用指定的函数。与基于ParamArray的东西(如ParameterizedThreadStart)不同,一切都是类型安全的。

例如,如果我说:

Sub Foo(param1 As Integer, param2 As String)
    ...
End Sub

...
  Dim theAct as Action(of Integer) = _
      ActionOf(of Integer).NewInv(AddressOf Foo,"Hello there")

  theAct(5)
...

结果将是在声明Foo的对象上调用Foo(5,“Hello there”)。不幸的是,我最终必须为我想要支持的每个不同数量的参数设置单独的泛型类和方法,但是将所有剪切和粘贴放在一个文件中比在每个地方散布额外的代码以创建适当的代表。