我知道副本有气味
但是如何重构代码?
public List<HighWay> updateAllNewHighWays(HighWayRepository repository)
throws IOException {
List<HighWay> highWays = new ArrayList<HighWay>();
for (RoadCode code : RoadCode.values()) {
try {
pageParam.setRoadName(code);
highWays.addAll(getAndSaveNewHighWay(repository));
} catch (IOException e) {
IOException exception = dealException(e, code);
throw exception;
}
}
return highWays;
}
public List<HighWay> getAllNewHighWays(HighWayRepository repository)
throws IOException {
List<HighWay> highWays = new ArrayList<HighWay>();
for (RoadCode code : RoadCode.values()) {
try {
pageParam.setRoadName(code);
highWays.addAll(getNewHighWay(repository));
} catch (IOException e) {
IOException exception = dealException(e, code);
throw exception;
}
}
return highWays;
}
答案 0 :(得分:1)
由于唯一改变的部分是循环的内部,你可以重构循环部分任何只有循环内的部分改变。
如果您使用Java 8,则可以将getAndSaveNewHighWay(repository)
或getNewHighWay(repository)
方法作为方法参考传递为Function<HighWayRepository, List<HighWay>>
实现
public List<HighWay> handleHighways(HighWayRepository repository, Function<HighWayRepository, List<HighWay>> function){
List<HighWay> highWays = new ArrayList<HighWay>();
for (RoadCode code : RoadCode.values()) {
try {
pageParam.setRoadName(code);
//call our method
highWays.addAll(function.apply(repository));
} catch (IOException e) {
IOException exception = dealException(e, code);
throw exception;
}
}
return highWays;
}
然后在你的主叫代码中:
List<HighWay> highways = handleHighways(repository, MyClass::getAndSaveNewHighWay);
或
List<HighWay> highways = handleHighways(repository, MyClass::getNewHighWay);
如果没有Java 8,您可以通过创建自己的接口来实现类似的功能,该接口的方法需要HighWayRepository
并返回List<HighWay>
,然后编写2个不同的实现
答案 1 :(得分:0)
请确保您具有可验证此类功能是否有效的测试(重构所有测试之前应以绿色运行)
将重复的逻辑复制并粘贴到新方法中(例如tobeReused,稍后您可以将其重命名为更好的方法)
使用lambdas参数化哪些变化(Java支持以下lambda类型:Runnable,Consumer,Predicate,Function)
在1.中重命名方法。为了不陷入 analysis-paralysis ,最好在理解后重新命名。
一个好的测试套件应该
关注行为测试
掩盖正面和负面的情景
封面案例
封面例外
测试名称应描述将要测试的内容而不是方法
每个测试的格式都应遵循“当下然后给出”或“安排行为声明”的格式。
可能的测试套件的示例代码结构:
public class HighwaysTest {
//Repository is valid
@Test
public void whenHighWayRepositoryIsValidThenHighWaysShouldBeSaved() {
}
//Repository is invalid
@Test
public void whenHighWayRepositoryIsInvalidThenHighWaysShouldBeSaved() {
}
//Wrong road code
@Test
public void whenRoadCodeIsInvalidThenPageParamIsNotUpdated() {
}
//Function getAndSaveNewHighWay fails
@Test
public void whenGetAndSaveNewHighWayFailsThenExceptionIsThrown() {
}
//Function getNewHighWay fails
@Test
public void whenGetNewHighWayFailsThenExceptionIsThrown() {
}
}
将重复的逻辑复制并粘贴到新方法中
private List<HighWay> tobeReused(HighWayRepository repository) throws IOException {
List<HighWay> highWays = new ArrayList<HighWay>();
for (RoadCode code : RoadCode.values()) {
try {
pageParam.setRoadName(code);
highWays.addAll(getAndSaveNewHighWay(repository));
} catch (IOException e) {
IOException exception = dealException(e, code);
throw exception;
}
}
return highWays;
}
使用lambdas(在这种情况下为Function<ParameterType, ReturnType>
)对变化进行参数设置:
private <P extends HighWayRepository,
R extends Collection> List<HighWay> tobeReused(P repository, Function<P, R> lambda) throws IOException {
List<HighWay> highWays = new ArrayList<HighWay>();
for (RoadCode code : RoadCode.values()) {
try {
pageParam.setRoadName(code);
highWays.addAll(lambda.apply(repository));
} catch (IOException e) {
IOException exception = dealException(e, code);
throw exception;
}
}
return highWays;
}
因为找到好名字可能很棘手,所以最好在掌握业务领域后再命名。然后可以将功能tobeReused
重命名为updatePageParamAndReturnHighways
:
public List<HighWay> updateAllNewHighWays(HighWayRepository repository) throws IOException {
Function<HighWayRepository, Collection> lambda = (repo) -> getAndSaveNewHighWay(repo);
List<HighWay> highWays = updatePageParamAndReturnHighways(repository, lambda);
return highWays;
}
public List<HighWay> getAllNewHighWays(HighWayRepository repository) throws IOException {
Function<HighWayRepository, Collection> lambda = (repo) -> getNewHighWay(repo);
List<HighWay> highWays = updatePageParamAndReturnHighways(repository, lambda);
return highWays;
}
您可能要考虑重构您的功能
updateAllNewHighWays
和getAllNewHighWays
,因为它们负有多项责任(更新pageParam
并返回高速公路)。