要干还是不干?关于避免代码重复和保持内聚性 [英] To DRY or not to DRY? On avoiding code duplication and retaining cohesion

查看:80
本文介绍了要干还是不干?关于避免代码重复和保持内聚性的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个关于代码复制和重构的问题,希望它不是太笼统.假设您有一段很小的代码(约5行),它是一系列函数调用的序列-不是很低的水平.此代码在多个地方重复,因此在此处提取方法可能是一个好主意.但是,在此特定示例中,此新功能将遭受低内聚性的影响(除其他外,这很难通过为该功能找到好名字来体现出来).这样做的原因可能是因为这些重复的代码只是更大算法的一部分-很难将其划分为命名良好的步骤.

I've got a question concerning code duplication and refactoring, hope it's not too general. Say you've got a rather small piece of code (~5 lines) which is a sequence of function invocations that is - not a very low level. This code is repeated in several places, so it would probably be a good idea to extract a method here. However, in this particular example, this new function would suffer from low cohesion (which manifests itself, among others, by having a hard time finding a good name for the function). The reason for that is probably because this repeated code is just a part of a bigger algorithm - and it's difficult to divide it into well named steps.

在这种情况下,您有何建议?

What would you suggest in such scenario?

我想将问题概括为一个整体,以便使更多的人有可能发现它有用,但是显然最好用一些代码示例对其进行备份.该示例可能不是有史以来最好的示例(它在很多方面闻起来都有),但我希望它能发挥作用:

I wanted to keep the question on a general level, so that more people can potentially find it useful, but obviously it would be best to back it up with some code sample. The example might not be the best one ever (it smells in quite a few ways), but I hope it does its job:

class SocketAction {

    private static class AlwaysCreateSessionLoginHandler extends LoginHandler {
        @Override
        protected void onLoginCorrect(SocketAction socketAction) throws IllegalAccessException, IOException {
            Server.checkAllowedDeviceCount(socketAction._sess.getDeviceID());
            socketAction.registerSession();
            socketAction._sess.runApplication();
        }
    }

    private static class AutoConnectAnyDeviceLoginHandler extends LoginHandler {
        @Override
        protected void onLoginCorrect(SocketAction socketAction) throws IllegalAccessException, IOException {
            if (Server.isUserRegistered(socketAction._sess.getUserLogin())) {
                Log.logSysInfo("Session autoconnect - acquiring list of action threads...");
                String[] sa = Server.getSessionList(socketAction._sess.getUserID());
                Log.logSysInfo("Session autoconnect - list of action threads acquired.");
                for (int i = 0; i < sa.length; i += 7) {
                    socketAction.abandonCommThreads();
                    Server.attachSocketToSession(sa[i + 1], socketAction._commSendThread.getSock());
                    return;
                }
            }
            Server.checkAllowedDeviceCount(socketAction._sess.getDeviceID());
            socketAction.registerSession();
            socketAction._sess.runApplication();
        }
    }

    private static class OnlyNewSessionLoginHandler extends LoginHandler {
        @Override
        protected void onLoginCorrect(SocketAction socketAction) throws IllegalAccessException, IOException {
            socketAction.killOldSessionsForUser();
            Server.checkAllowedDeviceCount(socketAction._sess.getDeviceID());
            socketAction.registerSession();
            socketAction._sess.runApplication();
        }
    }
}

推荐答案

问题过于笼统,无法真正说出,但是作为练习:

Question is too general to really say, but as an exercise:

假设您将其抽象.考虑一下想要更改生成的5行函数的可能原因是什么.您是否想做出可能适用于所有用户的更改,还是最终在每次调用者有理由要更改时都不得不编写与旧功能稍有不同的新功能?

Suppose you abstract it. Think about what the likely reasons are for wanting to change the resulting 5-line function. Would you want likely make changes that apply to all users, or would you end up having to write a new function that's slightly different from the old one, each time some caller has reason to want a change?

如果您想为所有用户更改它,那么这是一个可行的抽象.现在给它起一个不好的名字,您以后可能会想到一个更好的名字.

If you would want to change it for all users, it's a viable abstraction. Give it a poor name now, you might think of a better one later.

如果最终随着将来代码的发展而将此功能拆分为许多相似的版本,那么它可能不是可行的抽象方法.您仍然可以编写该函数,但是与其说,它是问题正式模型的一部分,不如说是节省代码的帮助器函数".这不是很令人满意:重复这么大量的代码有点令人担忧,因为这表明在某处应该是可行的抽象.

If you're going to end up splitting this function off into lots of similar versions as your code evolves in future, it's probably not a viable abstraction. You could still write the function, but it's more of a code-saving "helper function" than it is part of your formal model of the problem. This isn't very satisfactory: the repetition of this amount of code is a bit worrying, because it suggests there should be a viable abstraction in there somewhere.

也许5条线中的4条可以被抽象出来,因为它们更具凝聚力,而第五条线恰好在此刻徘徊.然后,您可以编写2个新函数:一个是这种新的抽象,另一个仅仅是调用该新函数然后执行第5行的助手.因此,其中一个函数的预期使用寿命可能比另一个函数更长.

Maybe 4 of the 5 lines could be abstracted out, since they're more cohesive, and the fifth line just so happens to be hanging around with them at the moment. Then you could write 2 new functions: one which is this new abstraction, and the other is just a helper that calls the new function and then executes line 5. One of these functions might then have a longer expected useful life than the other...

这篇关于要干还是不干?关于避免代码重复和保持内聚性的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆