Language agnostic 使用大量静态方法是一件坏事吗?
当一个类不需要跟踪内部状态时,我倾向于将该类中的所有方法声明为静态。例如,如果我需要将A转换为B,并且不依赖于某些可能变化的内部状态C,我将创建一个静态转换。如果有一个我希望能够调整的内部状态C,那么我将添加一个构造函数来设置C,而不使用静态转换 我阅读了各种建议(包括关于StackOverflow的建议),不要过度使用静态方法,但我仍然无法理解上面的经验法则有什么错Language agnostic 使用大量静态方法是一件坏事吗?,language-agnostic,static-methods,Language Agnostic,Static Methods,当一个类不需要跟踪内部状态时,我倾向于将该类中的所有方法声明为静态。例如,如果我需要将A转换为B,并且不依赖于某些可能变化的内部状态C,我将创建一个静态转换。如果有一个我希望能够调整的内部状态C,那么我将添加一个构造函数来设置C,而不使用静态转换 我阅读了各种建议(包括关于StackOverflow的建议),不要过度使用静态方法,但我仍然无法理解上面的经验法则有什么错 这是不是一个合理的方法?这似乎是一个合理的方法。您不想使用太多静态类/方法的原因是,最终您将从面向对象编程转向结构化编程领域 在
这是不是一个合理的方法?这似乎是一个合理的方法。您不想使用太多静态类/方法的原因是,最终您将从面向对象编程转向结构化编程领域 在您的例子中,您只是将A转换为B,那么我们所做的就是将文本从A转换为B
"hello" =>(transform)=> "<b>Hello!</b>"
“你好”=>(变换)=>“你好!”
那么静态方法就有意义了
但是,如果您经常在对象上调用这些静态方法,并且在许多调用中它往往是唯一的(例如,您使用它的方式取决于输入),或者它是对象固有行为的一部分,那么明智的做法是使它成为对象的一部分并保持其状态。一种方法是将其实现为一个接口
class Interface{
method toHtml(){
return transformed string (e.g. "<b>Hello!</b>")
}
method toConsole(){
return transformed string (e.g. "printf Hello!")
}
}
class Object implements Interface {
mystring = "hello"
//the implementations of the interface would yield the necessary
//functionality, and it is reusable across the board since it
//is an interface so... you can make it specific to the object
method toHtml()
method toConsole()
}
类接口{
方法toHtml(){
返回转换后的字符串(例如“Hello!”)
}
方法toConsole(){
返回转换后的字符串(例如“printf Hello!”)
}
}
类对象实现接口{
mystring=“你好”
//接口的实现将产生必要的
//功能,并且它是可重用的,因为
//是一个接口,因此…您可以使其特定于对象
方法toHtml()
方法toConsole()
}
编辑:Asp.NETMVC或Ruby中的html助手方法就是一个很好的静态方法使用示例。它们创建的html元素与对象的行为无关,因此是静态的
编辑2:将函数式编程更改为结构化编程(出于某种原因,我感到困惑),托尔斯滕指出了这一点。没有任何内部状态的对象是可疑的 通常,对象封装状态和行为。只封装行为的对象是奇怪的。有时它是轻量级或轻量级的一个例子
其他时候,它是用对象语言完成的过程设计。只要没有内部状态起作用,这就可以了。请注意,通常静态方法应该是线程安全的,因此如果使用帮助器数据结构,请以线程安全的方式使用它们。另一个选项是将它们作为非静态方法添加到原始对象上: i、 例如,改变:
public class BarUtil {
public static Foo transform(Bar toFoo) { ... }
}
进入
但是,在许多情况下,这是不可能的(例如,从XSD/WSDL/等生成常规类代码),否则会使类非常长,并且转换方法对于复杂对象来说往往是一个真正的难题,您只需要将它们放在它们自己的单独类中。因此,是的,我在实用程序类中有静态方法。警告您不要使用静态方法的原因是使用它们会丧失对象的一个优点。对象用于数据封装。这可以防止意外的副作用发生,从而避免错误。静态方法没有封装的数据,因此无法获得这种好处 也就是说,如果您不使用内部数据,那么它们可以很好地使用,并且执行起来稍微快一点。但是,请确保您没有接触其中的全局数据
- 有些语言还具有类级变量,允许封装数据和静态方法
因此,我的答案是,静态类并不是天生就坏的,但现在开始创建实例可能会更容易,以后再进行重构。有两种常见的静态方法:
- “安全”静态方法总是为相同的输入提供相同的输出。它不修改全局变量,也不调用任何类的任何“不安全”静态方法。本质上,您使用的是一种有限的函数式编程——不要害怕这些,它们很好
- “不安全”静态方法会改变全局状态、全局对象的代理或其他一些不可测试的行为。这些都是过程编程的回溯,如果可能的话应该重构
“不安全”静态有一些常见的用法——例如,在单例模式中——但是要注意,尽管你称它们为漂亮的名字,你只是在改变全局变量。在使用不安全的静态数据之前,请仔细考虑。如果您知道永远不需要使用C的内部状态,那就好了。但是,如果将来这种情况发生变化,您需要使该方法成为非静态的。如果一开始是非静态的,如果不需要内部状态,就可以忽略它。我过去常常在一个包含大量静态方法的类和一个单例类之间来回切换。两者都解决了问题,但是单例可以更容易地被多个单例替换。(程序员似乎总是很确定某件事只有一个,我发现自己错了很多次,完全放弃了静态方法,除了在一些非常有限的情况下) 不管怎么说,singleton使您能够稍后将某些内容传递到工厂以获得不同的实例,从而在不重构的情况下更改整个程序的行为。改变全球环境
public class Bar {
...
public Foo transform() { ...}
}
public class StaticClassVersionOne {
public static void doSomeFunkyThing(int arg);
}
StaticClassVersionOne.doSomeFunkyThing(42);
public static class ResourceLoader
{
public static void Init(string _rootPath) { ... etc. }
public static void GetResource(string _resourceName) { ... etc. }
public static void Quit() { ... etc. }
}
public static class TextureManager
{
private static Dictionary<string, Texture> m_textures;
public static Init(IEnumerable<GraphicsFormat> _formats)
{
m_textures = new Dictionary<string, Texture>();
foreach(var graphicsFormat in _formats)
{
// do something to create loading classes for all
// supported formats or some other contrived example!
}
}
public static Texture GetTexture(string _path)
{
if(m_textures.ContainsKey(_path))
return m_textures[_path];
// How do we know that ResourceLoader is valid at this point?
var texture = ResourceLoader.LoadResource(_path);
m_textures.Add(_path, texture);
return texture;
}
public static Quit() { ... cleanup code }
}
static cutNotNull(String s, int length){
return s == null ? null : s.substring(0, length);
}
public class BusinessService
{
public Guid CreateItem(Item newItem, Guid userID, Guid ownerID)
{
var newItemId = itemsRepository.Create(createItem, userID, ownerID);
**var searchItem = ItemsProcessor.SplitItem(newItem);**
searchRepository.Add(searchItem);
return newItemId;
}
}