如果您经常创建一个对象只是为了在其上调用方法,是否有代码味道?


14

我继承了一个代码库,其中有很多代码是这样的:

SomeDataAdapter sda = new SomeDataAdapter();
sda.UpdateData(DataTable updateData);

然后,不再使用sda。

那是一种代码气味,表明这些方法实际上应该是静态类方法吗?


这些类是否实现任何接口?
Reactgular 2014年

7
重构为静态方法的第二天就是要使用模拟版本的数据适配器运行单元测试的日子。
2014年

22
@Mike:为什么您需要模拟静态方法?我对静态方法不可测试的这种谬论感到非常厌倦。如果静态方法保持状态或产生副作用,那是您的错,而不是测试方法的错。
罗伯特·哈维

9
在我看来,这是一种语言气味,显示出“一切都必须是一类”分析的弱点。

7
@RobertHarvey:由于与模拟其他方法相同的原因,您可能需要模拟静态方法:在单元测试期间调用它太昂贵了。
凯文·克莱恩

Answers:


1

我认为这是一种体系结构气味,因为UpdateData可能应该属于“服务”类。

数据在哪里?AppleAdapter是服务/业务智能类。其中AppleService是对当前方法外部存在的AppleAdapter的Singleton引用。

private static volatile AppleAdapter _appleService = null;
private static object _appleServiceLock = new object();
private AppleAdapter AppleService
{
    get
    {
        if (_appleService == null)
        {
            lock (_appleServiceLock)
            {
                if (_appleService == null)
                    _appleService = new AppleAdapter();
            }
        }
        return _appleService;
    }
}

public SomeAppleRelatedMethod(Apple apple)
{
    AppleService.UpdateData(apple);
}

我认为您所做的不一定是错误的,但是如果SomeDataAdapter确实代表某种无状态业务服务,那么单例将是最佳的做法。希望有帮助!提供的示例是一种奇妙的方法,可以确保_appleService在没有任何争用并且恰好同时由两个或更多线程同时访问时不争用。

你知道吗?如果SomeDataAdapter是ADO IDbDataAdapter(几乎可以肯定是),请忽略整个响应!

:P

我无权向原始问题添加评论,但是如果您可以指定此代码存在的位置。

如果此代码表示IDbDataAdapter的自定义实现,并且UpdateData正在创建IDbConnection,IDbCommand并将其全部连接到幕后,那么不,我不会认为代码有异味,因为现在我们正在谈论流和其他当我们使用完它们后需要处理掉的东西。


12
救命!我淹没在软件模式中。
罗伯特·哈维

4
...或作为依赖项注入。;)
Rob

12
搞砸单例和双重检查锁定以获得等同于简单函数/过程的东西对我来说是一个更大的代码味道!
2014年

3

我认为这个问题比这更深。即使您确实将其重构为静态方法,也可以获得在各处调用单个静态方法的代码。我认为这本身就是代码气味。它可能表明您缺少一些重要的抽象。也许您想创建一个可以进行一些预处理和后处理的代码,同时允许您更改之间的处理方式。预处理和后处理将包含通用调用,而两者之间的调用将取决于具体的实现。


我同意存在一个更深层次的问题。我试图在不进行全面体系结构重新设计的情况下逐步改进它,但这听起来像是我认为不是一种好的方法。
Shane Wealti 2014年

1

的种类。通常,这意味着您想传递一个函数,而选择的语言不会让您失望。这有点笨拙和笨拙,但是如果您陷入一种没有一流功能的语言中,那么您将无能为力。

如果这些对象都不作为参数传递给其他函数,则可以将它们转换为静态方法,并且什么都不会改变。


这也可能意味着您希望静态方法返回传递给它的对象的修改后的版本(或修改后的副本)。
罗伯特·哈维

2
“如果您使用的语言没有一流的功能”:仅具有一个方法的对象与一流的功能(或一流的闭包)之间没有区别:它们只是相同视图的两个不同视图事情。
Giorgio 2014年

4
从理论上讲,不。在实践中,如果您的语言至少没有语法糖,那就是您之间fn x => x + 1和/ new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }};或将自己限制于一些硬编码且使用范围狭窄的函数之间的区别。
2014年

为什么不能fn x => x + 1使用语法糖new Function<Integer, Integer>() { public Integer eval(Integer x) { return x + 1; }}呢?好吧,也许你的意思是如果一个人陷入一种没有这种语法糖的语言中。
乔治

@Giorgio您必须询问Oracle。(当然,Java 8终于改变了这一点)。请注意,要真正有用,您不仅需要更多语法糖-您还希望能够按名称传递预先声明的方法。咖喱也很方便。在某个时候,您不得不怀疑是否值得拥有所有这些技巧,而不是将职能视为第一位公民。但是现在我变得不合时宜了。
2014年

0

如果保持状态使给定的类更具实用性,功能性……可重复使用,则否。由于某种原因,我想到了命令设计模式。这个原因当然不是要让罗伯特·哈维淹死。


0

定义“经常”。怎么样往往你实例化对象?很多-可能不是吗?

您的系统中可能需要担心更大的问题。静态化将与程序员更清楚地传达该对象的内部状态没有改变-很好。

如果状态被弄乱了,并且您必须开始将其他事物变为静态以使第一件事变为静态,那么您必须询问哪些部分需要静态,哪些部分不需要静态。

是的,它只是一种代码气味,只是很小的一种。


0

使其成为静态方法,然后继续。静态方法没有错。一旦出现了使用模式,您就可以担心将其抽象化。


0

这里的气味是这是(最少)包装在对象中的过程代码。

您一定有理由要在数据表上执行该操作,而不是使用共享某些语义(即,具有共同含义)的其他相关操作对该操作进行建模,而作者只是在一个新的内部创建了一个新过程。类并称之为。

在函数式语言中,这就是您要做的事情;)但在OO范式中,您需要建模包含该操作的抽象。然后,您将使用OO技术充实该模型并提供一组保留某些语义的相关操作。

因此,这里的主要气味是作者正在使用类,这可能是因为编译器需要它,而没有将操作组织到概念模型中。

顺便说一句,当您看到正在建模的程序而不是问题空间时,请当心。这表明设计可以从更多的思考中受益。换句话说,当心所有类都是“ xAdaptor”,“ xHandler”和“ xUtility”,并且通常与贫血领域模型联系在一起。这意味着某人只是为了方便而捆绑了代码,而不是实际地建模他们想要实现的概念。

By using our site, you acknowledge that you have read and understand our Cookie Policy and Privacy Policy.
Licensed under cc by-sa 3.0 with attribution required.