是否可以使用大多数静态类?

时间:2010-03-09 16:23:32

标签: php design-patterns static-methods

我目前正在重写一个电子商店 - 但只有客户端,即CMS仍然主要是机智。我没有使用预先构建的框架,因为系统必须保持与CMS的向后兼容性,我必须完全自由地使用代码结构。

新系统纯粹基于MVC,我有一个Bootstrapper,它根据当前的uri加载控制器,后者使用模型进行实际工作 - 包括会话和数据库。

tl; dr 这是我的第一个没有预建框架的项目。

在设计模式方面我很缺乏经验。我知道大多数受欢迎的工作如何工作但从未使用过。

现在我怀疑代码气味,因为我的所有模型都是纯粹由静态方法组成的类。我发现以不同的方式做这些事情没有任何好处。我通常需要在代码中的各个地方使用一些方法。即我需要在主布局中获取登录用户,检查用户权限以查看bootstraper中的当前页面,由控制器显示用户面板。如果我不使用静态,我需要每次重新实例化一个对象或保持全局对象。一次也不需要多于一个这样的课程。

我必须遗漏一些东西,因为即使我使用OOP,我的一些类对于他们的方法来说只是毫无意义的容器(有时是一些私有变量)。我本可以使用PHP4和简单的函数。

任何意见或建议都将受到高度赞赏。

编辑:尽管有这些受过良好教育的答案,我仍然不相信。虽然这很可能是因为我缺乏经验,但我仍然没有预见到当前的设置会出现什么问题。我的意思是我甚至不知道由于现在的代码架构而给我带来任何不便的情况。我希望我没有得到一个严厉的教训,因为改变任何事情为时已晚......

7 个答案:

答案 0 :(得分:5)

你是对的,这是代码味道,每个人都会告诉你它是baaaad。

所以在这里我建议对问题的严重程度进行自我评估

  • 您是否有许多 getter和setter 的课程?

  • 您的静态功能如下所示吗?

    如果是,请尝试移动类MyClass中的逻辑,该逻辑将更多OO。这是程序/脚本世界的一个经典错误。


 static void myMethod( MyClass anObject )
 {
     // get value from anObject
     // do some business logic
     // set value of anObject
 }

  • 您是否有很多全局状态,例如您从当前会话中获取的数据?

    如果是,请评估您是否要更改它。 OO方式是将会话传递给调用链。但实际上,将会话作为全局对象访问会很方便。但它阻碍了可测试性。尝试删除一些全局状态并将其转换为您在方法中传递和操作的常规对象。

进行此评估,并尝试识别实用程序类,服务类和业务对象。实用程序类是具有实用方法(例如格式化,转换等)的辅助类,它们可以是静态的。服务类做一些业务逻辑,但它们应该是无状态的,一个实例就足够了。业务对象为userproductsarticle等,您必须集中精力。尝试将普通数据转换为嵌入某些行为的对象。

看看should entity be dumb。即使它是用于java,概念也是通用的。

修改

以下是根据您的评论进行的分析:

  • 您没有包含实体的域模型。您可以直接操作数据库。
  • 您所谓的模型,就是我所说的服务,是您执行操作数据的业务逻辑的地方。服务类是无状态,这是正确的。正如您在问题中指出的那样,您需要不断重新创建它们,创建一个全局实例或使用静态方法。

OO范例会说你应该尝试使用域模型来将数据库映射到实体。至少有一个anemic domain model,其中实体是在数据库中加载/保存的枯燥数据容器。然后OO范例也会说如果可能的话在实体中加入一些逻辑。

它还会说将服务转化为对象以简化组合和重用。如果是这种情况,您可以使用拦截器包装所有服务来启动/停止事务或进行一些安全检查,这将无法使用静态方法。

您描述的内容(没有实体+无状态程序服务)不被认为是一个伟大的OO设计。我建议你至少引入贫血领域模型DAO。关于无懈可击的程序服务,这实际上是许多Web应用程序的现实 - 如果您不需要更多,您可以坚持下去。

我的2美分

答案 1 :(得分:4)

如果你主要只使用静态类,那么你真的从面向对象的编程中取出了对象。我并不是说你做错了事,我说也许你的系统不应该用于OOP。也许它是一个简单的应用程序,需要一些基本的实用功能(发送电子邮件等)。在这种情况下,大多数代码都变得非常程序化。

如果您正在处理数据库,您可以拥有一个静态数据库类和一个简单的业务层,您的php应用程序将与您的业务层进行交互,而业务层又与您的数据库层进行交互。这成为典型的3层架构(有些人喜欢将其称为4个层,并从数据层中分离出实际的数据库,同样的事情)。

如果你真的没有调用需要一个对象的方法而不是所有这些静态类的方法,那么只需要问一个问题。

答案 2 :(得分:4)

您可能注意到的一件事是,如果您打算使用模拟/存根进行任何类型的单元测试,您可能会遇到困难,因为静态类和方法不容易模拟,存根或测试。

答案 3 :(得分:1)

我会谨慎地在Web应用程序中使用静态变量和类。如果你真的必须在用户之间共享实例,那么应该可以使用单个实例(查找“Singleton”设计模式)。

但是,如果您尝试跨页维护状态,则应通过使用ViewState或使用Session对象来执行此操作。

如果你有一个全局静态变量,你可能会遇到并发用户正在努力更新相同值的情况。

答案 4 :(得分:1)

简短的回答:没关系,但是你已经超越了OOP的好处。

使用对象背后的一个原因是,大多数情况下,有多种类型的对象执行角色。例如,您可以将DBVendor1数据访问对象与具有相同接口的DBVendor2数据访问对象交换。如果您正在使用单元测试并且需要交换与虚拟对象(模拟和存根)进行实际工作的对象,这尤其方便。您可以使用与乐高积木相同的界面来考虑您的物体,这些积木具有不同的颜色,可以轻松互换。而你根本无法用静态对象做到这一点。

当然,增加对象的灵活性是有代价的:对象的初始化并将它们放在一起是更多的工作(就像你写的那样),并导致更多的代码和对象将其他对象组合在一起。这就是builderfactory等创作设计模式发挥作用的地方。

如果你想走那条路,我建议你阅读dependency injection并使用DI framework

答案 5 :(得分:1)

从技术上讲,这样做没有错。但实际上,您正在失去面向对象编程的许多好处。还要编写它所属的代码/功能..例如:

 user.doSomeTask()
用户对象上的

更有意义
 UserUtils.doSomeTask(User user)

使用OOP概念,您可以抽象它所属的功能,将来它可以帮助您更改代码,比使用静态方法更容易扩展功能。

答案 6 :(得分:-1)

使用静态方法有一些优点。一个是因为你不能继承它们,所以它们的表现更好。但是一直使用它们会限制你。整个OOP范例 基于继承的使用,基于基类的可重用性。