- android - RelativeLayout 背景可绘制重叠内容
- android - 如何链接 cpufeatures lib 以获取 native android 库?
- java - OnItemClickListener 不起作用,但 OnLongItemClickListener 在自定义 ListView 中起作用
- java - Android 文件转字符串
在理论上的数据库访问类中,我发现我在类中使用了相当多的辅助函数,它们与类的实例无关(还有其他一些,可以被操作为与类的实例无关使用依赖注入(inject))。
例如,我有一个函数可以获取变量中两个其他字符串之间的字符串。我一直在考虑将其移至 String_Helper 类或类似的东西。此函数已设为静态。
此外,我还有一个查询数据库的函数,query($sql)
。连接详细信息由实例提供,但我一直在考虑将其设为静态,并使用 query($sql, $connection)
。然后,开发人员将能够静态调用它,根本不需要实例化数据库类。
对我来说,问题是:
做这样的事情值得吗?像查询函数这样的函数让我想知道这是否不仅仅是我在没有任何真正需要的情况下试图让一切尽可能静态。您认为这在什么情况下有用?
我知道静态函数更难测试,但如果我确保它们的代码完全没有依赖性(或在必要时使用依赖注入(inject)),那么它们就和其他一切一样容易测试,当然?
目前这不是问题,但如果将来我决定用静态函数扩展类,我就不可能让当前代码使用我的扩展函数。我想到了单例,但出现了同样的问题:代码将调用 Singleton_Class::getInstance()
,而不是 My_Extended_Singleton_Class::getInstance()
。依赖注入(inject)似乎是解决此问题的唯一方法,但它可能会导致 API 更笨重,因为每个依赖项都必须赋予 __construct()
上的对象。
我有一个容器类,它静态保存某些信息片段,以便可以在脚本的任何位置(全局范围)访问它们。如果我不能使用静态函数或单例,那么包含不同变量实例的类会很棒。例如可以使用 Container::$objects['MyClass'] = $MyClass_object;
,然后剩下的代码就可以访问 Container::$objects['MyClass']
。如果我扩展 MyClass 类,我可以使用 Container::$objects['MyClass'] = $MyExtendedClass_object;
,以及使用 Container::$objects['MyClass'] 的代码
将使用 MyExtendedClass,而不是 MyClass。在我看来,这是迄今为止最好的方法,但我想知道您对此有何看法。
最佳答案
好吧,让我一一回答...
<强>1。这样做值得吗
是也不是。将辅助函数拆分到它们自己的类中是个好主意。它严格定义了每个类的“范围”,并且您不会犯错。但是,不要仅仅因为可以就将方法设为静态。查询方法可以通过管理连接让您的生活更轻松,那么您为什么要失去这种好处呢?
<强>2。它们更难测试
它们并不难测试。依赖于状态的静态方法更难测试(访问静态成员变量或全局变量)。但静态方法通常与实例方法一样易于测试(事实上,它们可能更容易,因为您无需担心实例化)。
<强>3。扩展类
这是一个合理的担忧。如果将 String_Helper::foo()
放在类本身中,就会遇到问题。但是一个选项是将字符串助手的名称设置为类变量。所以您可以执行 {$this->stringHelper}::foo()
(注意,仅限 PHP 5.3)。那种覆盖类的方法,您需要做的就是更改该实例中的字符串助手类。 Lithium
框架做了很多...
<强>4。全局注册中心
我会远离这个。您基本上只是在不强制执行的情况下使每个类都成为单例。测试将是一场噩梦,因为您现在依赖于全局范围。相反,我会创建一个注册表对象并通过构造函数(依赖注入(inject))将其传递给类。你仍然完成同样的事情,因为你有一个对象/类的存储,但你不再依赖于全局范围。这使测试变得更加容易。
一般情况
当你正在考虑做这样的事情时,我喜欢在遇到这样的问题时停下来。停下来坐下来思考 *我要解决的实际问题是什么?”。明确列举问题。然后提取我们假设的解决方案,看看它们是否真正解决了它们。如果他们这样做了,那么想想 future ,如果这些解决方案从长远来看确实是可维护的(无论是从错误修复的角度,还是从功能添加的角度来看)。只有当你对这两个答案都满意时,你才应该考虑这样做。哦,还要记住保持简单. 编程不是要做出最复杂、最聪明或最惊人的解决方案。它是要做出解决问题的最简单的方案...
希望对你有帮助...
祝你好运!
关于php - PHP中静态方法的缺点,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/4463314/
我想了解 Ruby 方法 methods() 是如何工作的。 我尝试使用“ruby 方法”在 Google 上搜索,但这不是我需要的。 我也看过 ruby-doc.org,但我没有找到这种方法。
Test 方法 对指定的字符串执行一个正则表达式搜索,并返回一个 Boolean 值指示是否找到匹配的模式。 object.Test(string) 参数 object 必选项。总是一个
Replace 方法 替换在正则表达式查找中找到的文本。 object.Replace(string1, string2) 参数 object 必选项。总是一个 RegExp 对象的名称。
Raise 方法 生成运行时错误 object.Raise(number, source, description, helpfile, helpcontext) 参数 object 应为
Execute 方法 对指定的字符串执行正则表达式搜索。 object.Execute(string) 参数 object 必选项。总是一个 RegExp 对象的名称。 string
Clear 方法 清除 Err 对象的所有属性设置。 object.Clear object 应为 Err 对象的名称。 说明 在错误处理后,使用 Clear 显式地清除 Err 对象。此
CopyFile 方法 将一个或多个文件从某位置复制到另一位置。 object.CopyFile source, destination[, overwrite] 参数 object 必选
Copy 方法 将指定的文件或文件夹从某位置复制到另一位置。 object.Copy destination[, overwrite] 参数 object 必选项。应为 File 或 F
Close 方法 关闭打开的 TextStream 文件。 object.Close object 应为 TextStream 对象的名称。 说明 下面例子举例说明如何使用 Close 方
BuildPath 方法 向现有路径后添加名称。 object.BuildPath(path, name) 参数 object 必选项。应为 FileSystemObject 对象的名称
GetFolder 方法 返回与指定的路径中某文件夹相应的 Folder 对象。 object.GetFolder(folderspec) 参数 object 必选项。应为 FileSy
GetFileName 方法 返回指定路径(不是指定驱动器路径部分)的最后一个文件或文件夹。 object.GetFileName(pathspec) 参数 object 必选项。应为
GetFile 方法 返回与指定路径中某文件相应的 File 对象。 object.GetFile(filespec) 参数 object 必选项。应为 FileSystemObject
GetExtensionName 方法 返回字符串,该字符串包含路径最后一个组成部分的扩展名。 object.GetExtensionName(path) 参数 object 必选项。应
GetDriveName 方法 返回包含指定路径中驱动器名的字符串。 object.GetDriveName(path) 参数 object 必选项。应为 FileSystemObjec
GetDrive 方法 返回与指定的路径中驱动器相对应的 Drive 对象。 object.GetDrive drivespec 参数 object 必选项。应为 FileSystemO
GetBaseName 方法 返回字符串,其中包含文件的基本名 (不带扩展名), 或者提供的路径说明中的文件夹。 object.GetBaseName(path) 参数 object 必
GetAbsolutePathName 方法 从提供的指定路径中返回完整且含义明确的路径。 object.GetAbsolutePathName(pathspec) 参数 object
FolderExists 方法 如果指定的文件夹存在,则返回 True;否则返回 False。 object.FolderExists(folderspec) 参数 object 必选项
FileExists 方法 如果指定的文件存在返回 True;否则返回 False。 object.FileExists(filespec) 参数 object 必选项。应为 FileS
我是一名优秀的程序员,十分优秀!