我目前正在使用HibernateConstraintValidator来实现我的验证。但是我的审阅者不喜欢在代码或!运算符中使用if/其他。我可以使用哪种设计模式来删除验证逻辑中的if/其他?
public class SomeValidatorX implements ConstraintValidator<SomeAnnotation, UUID> {
@Autowired
SomeRepository someRepository;
@Override
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
}
在下面的代码中,他不想要if/否则
public class SomeValidatorY implements ConstraintValidator<SomeAnnotation, SomeClass> {
@Autowired
SomeRepository someRepository;
@Override
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
}
}
附带说明:我们必须使用域驱动设计(如果有帮助的话)
您可以检查空html" target="_blank">对象模式。一般模式是在代码中完全禁止< code>null。这消除了难看的< code>null检查。在这一点上,我同意你的代码审查。
遵循以下建议将导致:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
在引入空对象模式之前,只需应用该模式或约定来强制初始化所有引用。这样,您可以确保整个代码中没有< code>null引用。< br >因此,当您遇到< code > NullPointerException 时,您不会通过引入< code>null检查来解决问题,而是通过初始化引用(在构造时)来解决问题,例如,通过使用默认值、空集合或空对象。
大多数现代语言都支持通过像< code>@NonNull这样的注释进行代码分析,这种注释检查像参数这样的引用,并在参数为< code > null /未初始化时抛出异常。例如,< code>javax.annotation就提供了这样的注释。
public void operation(@NonNull Object param) {
param.toString(); // Guaranteed to be not null
}
使用此类注释可以保护库代码免受空参数的影响。
您可以使用有意义的值或专用的空对象来初始化每个引用,而不是使用null
引用:
定义空对象合约(非必需):
interface NullObject {
public boolean getIsNull();
}
定义基本类型:
abstract class Account {
private double value;
private List<Owner> owners;
// Getters/setters
}
定义空对象:
class NullAccount extends Account implements NullObject {
// Initialize ALL attributes with meaningful and *neutral* values
public NullAccount() {
setValue(0); //
setOwners(new ArrayList<Owner>())
@Override
public boolean getIsNull() {
return true;
}
}
定义默认实现:
class AccountImpl extends Account implements NullObject {
@Override
public boolean getIsNull() {
return true;
}
}
使用Null帐户
类初始化所有帐户
引用:
class Employee {
private Account Account;
public Employee() {
setAccount(new NullAccount());
}
}
或者使用 NullAccount
返回失败的状态实例(或默认值),而不是返回 null
:
public Account findAccountOf(Owner owner) {
if (notFound) {
return new NullAccount();
}
}
public void testNullAccount() {
Account result = findAccountOf(null); // Returns a NullAccount
// The Null-object is neutral. We can use it without null checking.
// result.getOwners() always returns
// an empty collection (NullAccount) => no iteration => neutral behavior
for (Owner owner : result.getOwners()) {
double total += result.getvalue(); // No side effect.
}
}
您可以使用的另一种模式是Try-Do模式。您只需测试操作本身,而不是测试操作的结果。操作负责返回操作是否成功。
在文本中搜索字符串时,返回布尔值(无论结果是否找到)可能更方便,而不是返回空字符串甚至更糟的 null
:
public boolean tryFindInText(String source, String searchKey, SearchResult result) {
int matchIndex = source.indexOf(searchKey);
result.setMatchIndex(matchIndex);
return matchIndex > 0;
}
public void useTryDo() {
SearchResult result = new Searchresult();
if (tryFindInText("Example text", "ample", result) {
int index = result.getMatchIndex();
}
}
在您的特殊情况下,您可以将findByAAndB()
替换为containsAAndB):布尔
实现。
最终的解决方案实现了Null Object模式并重构了find方法。原来的<code>findByAAndB()</code>的结果以前被丢弃了,因为您想测试<code>A</code>和<code>B</code>的存在性。另一种方法<code>public boolean contains()</code>将改进代码
重构的实现如下所示:
abstract class FieldA {
}
class NullFieldA {
}
class FieldAImpl {
}
class SomeClass {
public SomeClass() {
setFieldA(new NullFieldA());
}
}
改进的验证:
public boolean isValid(SomeClass someObject, ConstraintValidationContext context) {
return someRepository.containsAAndB(someObject.getFieldA(), B);
}
很久以前,在时间的开端。有一个指导方针说方法应该只有一个出口点。为了实现这一点,开发人员必须跟踪本地状态,并使用if/else来到达方法的结尾。
今天我们更了解了。通过尽可能早地退出一个方法,在阅读代码时更容易将整个流程保持在头脑中。更简单的代码意味着更少的错误。更少的错误等于更少的错误。
在我看来,这就是审阅者不喜欢代码的原因。它并不像它可能的那样容易阅读。
让我们举第一个例子:
public boolean isValid(UUID uuid, ConstraintValidationContext context) {
return !(uuid!=null && someRepository.existsById(uuid)); //The reviewer doesn't want this negation operator
}
代码所说的是“不是这样的:(uuid不应该为空,它必须存在)”。这很容易理解吗?我想不是。
替代方案:“如果uuid不存在,没关系,但如果存在,该项目可能不存在”。
或在代码中:
if (uuid == null) return true;
return !someRepository.existsById(uuid);
更容易阅读,对吧?(我希望我的意图是正确的;)
第二个例子
if(someObject.getFieldA() != null) { //He doesn't want this if statement
//do some operations
List<Something> someList = someRepository.findByAAndB(someObject.getFieldA(),B);
return !someList.isEmpty(); //He doesn't want this ! operator
}
return false; // He was not fine with else statement in here as well
好的。你在这里说:
更简单的结论是:
转换为代码:
if (someObject.getFieldA() == null)
return true;
return !someRepository.findByAAndB(someObject.getFieldA(),B).isEmpty();
在C#中,我们有Any()
,它与isEmpty
有时需要否定。在存储库中编写一个新方法来避免它是没有意义的。但是,如果
findByAAndB
仅用于此,我会将其重命名为ensureCombination(a,b)
,以便在有效情况下返回true。
当你说话的时候试着写代码,这会让你更容易在脑海中描绘代码。你不是在说“我没吃饱,我们去吃午饭吧”,是吗?;)
在网上搜索和阅读了关于设计模式的文章后,我发现了三种类型,即行为型、创造型和结构型设计模式(GOF)。
我编写了一个程序来解析XML文件,以获取一个名为SerialNum的特定标记值,该值包含在Header标记中。该文件的构造如下: < li >它包含一个标题和一个正文 < li >标题可能包含许多SerialNum标签。我们需要提取最后一个标签的值。 我使用Stax解析器获取SerialNum值,并编写了以下代码: 此代码提取所需的值,但代码质量不是很好:它不容易阅读和维护。它包含一个开关案例,如
目前我有3个类,其中大多数变量是相同的。所有变量都有getter和setter。我需要根据提供的数据类型变量Year创建类的对象,并在十多个方法中传递该对象。让我们举个例子。 我们有三个班,A班,B班,C班。如果我们通过2017年,那么我需要ClassA的目标。如果我们通过2016年,那么我需要B类的目标,而对于所有其他年份,我们需要C类的目标。 然后,我们需要在所有10个方法中传递该对象。让我们
在众所周知的设计书《Domain-Driven Terms》中,它被描述为: 设计模式是命名、抽象和识别对可重用的面向对象设计有用的的通用设计结构。设计模式确定类和他们的实体、他们的角色和协作、还有他们的责任分配。 每一个设计模式都聚焦于一个面向对象的设计难题或问题。它描述了在其它设计的约束下它能否使用,使用它后的后果和得失。因为我们必须最终实现我们的设计模式,所以每个设计模式都提供了例子..代码