2009-09-01 55 views
3

我今天遇到了类似这样的代码;具有对整个班级可见的流量控制标志。我的直觉告诉我们,这是处理流量控制需求的错误方法(它几乎就像C中的旧时代的全球旗帜)。全局变量仍然不好?

(这个例子是在VB.Net,但类似的事情可能在C#来完成。)

Public Class myClass 

    Private bMyFlag As Boolean ''// <------ 

    private sub New 
     bMyFlag = false 
    end sub 

    private sub mySub1 
     bMyFlag = true 
     mySub3() 
     mySub4() 
     mySubN() 
    end sub 

    private sub mySub2 
     bMyFlag = false 
     mySub3() 
     mySub4() 
     mySubN() 
    end sub 

    private sub mySub3 
     if bMyFlag then 
      DoSomething() 
     else 
      DoSomethingElse() 
     end if 
    end sub 

    private sub mySub4 
     if not bMyFlag then 
      DoSomethingDifferent() 
     else 
      DoSomethingReallyDifferent() 
     end if 
    end sub 

    private sub mySubN 
     if not bMyFlag then 
      DoNotPassGo() 
     else 
      DoNotCollect200Dollars() 
     end if 
    end sub 
end class 

很明显,我认为这是事实后嫁接。我打算重新编写代码,以便bMyFlag是传递给mySub3,mySub4和mySuvN的参数。但是,在我这样做之前:

是否有一个有效的理由让流控制标志对类是全局的?

如果不是,为什么这被认为是不好的做法?

+1

我不打算发布一个完整的答案,但你应该了解得墨忒耳定律:HTTP:// EN .wikipedia.org/wiki/Law_of_Demeter – 2009-09-01 21:09:47

回答

7

在这种情况下,bMyFlag似乎正在引入不必要的状态,这可能会使开发(调试等)复杂化。一些子程序修改了它的值,其他的子程序根据它的当前值执行不同的操作。这似乎引入了不必要的复杂性,可以通过一些重构来减少复杂性。为什么不传递一个布尔值到mySub1mySub2,然后让这些子程序调用你的其他函数作为参数?

+2

是的,将一个布尔值明确地传递给mySub1和mySub2是我的计划 – BIBD 2009-09-01 21:19:27

+0

er。,make mySub3,mySub4和mySubN – BIBD 2009-09-01 21:31:45

+0

看起来像一个方法设置状态并执行一些init,另一个方法设置不同的状态并执行其他初始化。然后对象的行为相应。几乎不值得。 (根据发布的代码。) – snarf 2009-09-01 23:23:27

9

我不认为这真的是一个“全球”。它只是一个成员级别的字段。在大多数情况下,这是完全可以接受的(但不是真正的流量控制 - 看起来你真正需要的是重新设计一些类)。

12

这不是全局变量(即应用程序范围)变量,它是实例级别(即范围限于类)没有任何问题,只要这是预期的。

所以当这个标志为真时,如果它对于整个实例是真的,那就是它应该在的地方。如果每次都以完全不同的方式使用某种通用的东西,那么就不应该在那里声明它。

+4

我认为你忽略了甜甜圈提到的事实 - 2种方法根据标志的值做不同的事情。那,恕我直言,这里是最大的味道。 – 2009-09-01 21:29:18

+0

考虑到psudo代码的通用性,我认为很难说明任何内容。虽然甜甜圈可能是正确的,但可能有依赖于该状态持续存在的方法。没有进一步澄清,我认为不可能明确地说这是做对事情的正确或错误的方式。 – 2009-09-01 23:15:47

+0

根据发布的“模糊”代码,类字段可能(可能是?)影响其行为的对象状态(即类似“缓存数据”或“适用于所有用户”)。也许有些东西可以更好地抽象出来,但它看起来并不荒谬或可怕。 – snarf 2009-09-01 23:20:25

2

There are很多时候,当它是有效的有你指的模式。毕竟,对象是数据+操作,在你的例子中bMyFlag只是一些对象数据(状态)。如果其他方法不使用bMyFlag,并且只有mySub3,mySub4,mySubN这样做,那么你可以使它成为它们的一个参数。否则,按原样离开它是合理的,如果它封装了实例的某个有用状态,则bMyFlag是该类的有效实例成员。

1

有一些内部变量来存储状态是好的,但只有(在我看来)当你想让你的对象暴露一个接口的状态。在这种情况下,它被私有方法使用,这对我来说只是不好的设计。

1

如果您的示例代码反映了真实的代码,我会说使用标志成员是一种不好的做法。 Mysub3,mysub4等实际上是在做两件不同的事情,所以它们应该是不同的方法。因此根本不需要旗帜。

+0

在mySub3和mySub4中还有更多的东西正在进行中,我简化了它。就像在我们记录到文本文件的情况下,而另一个我们正在将消息扔到屏幕上。 – BIBD 2009-09-01 21:25:36

+0

是的,但是然后你必须有一个外部实体根据对象的状态来决定调用哪个方法。对我而言,这比实施的方式更糟糕。你会在不需要的类之间引入耦合。我认为,班级应该根据自己的状态知道如何独立行事。问题在于最简单和最干净的方法是什么。不过,它们不一定是相同的。 – tvanfosson 2009-09-01 21:26:34

+1

@CodeSlave - 基于你的评论,这听起来像你应该为此使用继承。你有一种登录到数据库的对象和一种登录到屏幕的对象。它们应该从相同的基类中派生出来,但是你应该创建你需要的类。我不会将该标志引入方法参数。 – tvanfosson 2009-09-01 21:28:22

4

很难从一个人为的例子说,但你可能要考虑引入战略模式来处理基于对象的状态的不同行为。通过这种方式,你可以实现不同的行为作为可互换的策略。这些策略将根据对象的状态交换进/出。每种方法都会简单地为其行为调用当前策略。当然,如果策略复杂或众多,我只会这样做。

对于某些合理简单的你也可以使用继承,例如,我有两种状态:只读和可编辑。锁定对象需要一个Editable对象并返回该对象的只读版本。实际上,只有一个对象,但是你有可编辑和只读的包装。行为的差异被内置到包装中(如果您尝试更改某些内容,只读对象会引发异常)。

如果它非常简单,并且没有普及,我没有看到任何真正的问题,保持它的方式。最终if/else的东西会变得复杂和丑陋,那么你可以重构更干净的东西,就像我上面所描述的那样。

更新根据您的意见:

听起来真是你有一个问题是可解与继承。你想要一个LoggableObject。这个LoggableObject有两个不同的变体:ScreenLoggable和FileLoggable。为ILoggable和一个包含任何公共代码的抽象基类定义一个接口。然后定义一个写入屏幕的ScreenLoggable类,它应该从您的基类继承,并包含写入屏幕的代码的变体。定义写入文件的FileLoggable类。它也应该从您的基类继承,但包含写入文件的变体。根据您的标志使用工厂创建您需要的ILoggable类型。根据界面使用它,它会做正确的事情。

+0

我对有关日志记录的评论只是可能发生的一个例子。但是,注意到和+1。 – BIBD 2009-09-01 21:40:03

0

这不是全球性的,但它仍然凌乱。如果它只用了几次,那么也许它可以简单地离开,但是任何超过2或3倍的东西,你应该将不同的功能提取到其他类中。

如果你想保持所有的代码都是本地的,你可以在其中嵌套类。像下面的(对不起,如果vb的语法是错误的,它已经有一段时间)有些事情

Public Class myClass 

Private bMyobj As iThing ' <------ 

Private Sub New() 
    bMyobj = null 
End Sub 

Private Sub mySub1() 
    bMyobj = New Thing2() 
    mySub3() 
    mySub4() 
    mySubN() 
End Sub 

Private Sub mySub2() 
    bMyobj = New Thing1() 
    mySub3() 
    mySub4() 
    mySubN() 
End Sub 

Private Sub mySub3() 
    bMyObj.DoSomething() 
End Sub 

Private Sub mySub4() 
    bMyObj.DoSomethingDifferent() 
End Sub 

Private Sub mySubN() 
    bMyObj.PassGo() 
End Sub 


Public Interface iThing 
    Sub DoSomething() 
    Sub DoSomethingDifferent() 
    Sub PassGo() 
End Interface 

Public Class Thing1 
    Implements iThing 

    Public Sub DoSomething() 
     ' Implementation 1 
    End Sub 
    Public Sub DoSomethingDifferent() 
     ' Implementation 1 
    End Sub 
    Public Sub PassGo() 
     ' Don't do it 
    End Sub 
End Class 
Public Class Thing2 
    Implements iThing 
    Public Sub DoSomething() 
     ' Implementation 2 
    End Sub 
    Public Sub DoSomethingDifferent() 
     ' Implementation 2 
    End Sub 
    Public Sub PassGo() 
     ' Don't collect 200 dollars 
    End Sub 
End Class 

End Class 
+0

这是国家模式,正是我所想的。 (但是有一个错字:在bMyFlag中,我认为你的意思是“bMyobj =”而不是“bMyFlag =”。) – Anon 2009-09-01 22:23:48

+0

(在mySub2()中,而是纠正我自己的错字)。 – Anon 2009-09-01 23:07:17

+0

不能相信这没有得票。我没有注册,所以不能投票,但精神+1!如果实际要求只是 - 或者没有保存状态的记录,那当然是完全不同的,但是根据问题中显示的代码保存和切换状态,我最喜欢这个答案。 – Anon 2009-09-03 15:37:14