我注意到我的代码看起来非常难看,很难维护。基本上,我需要做一些人检查。伪代码是这样的(BTW我可以' t" cut"查询中的任何内容,并且它不是我的问题的重点):
List<Person> persons = getPersonsBySomeQuery();
if (checkAnyPersonExists(persons)) {
if (atLeastOneWithGivenNameExist(persons)) {
if (noOneWithOtherNameExists(persons)) {
filteredPersons = filterPersonsWithGivenName(persons);
if (singleName(filteredPersons)) {
// single person found
if (someParameterFromQueryIsTrue) {
if (someComplicatedLogicIsOK) {
// found exactly one person, all OK!!!
} else {
// found exatcly one person with given name, but not OK
}
} else {
// found exactly one person but parameter from query is not OK
}
} else {
// found only persons with given name, but more then one
}
} else {
// found person(s) with given name, but also some with different name
}
} else {
// found person(s), all have different name
}
} else {
// noone found
}
所以我没有那么多设计模式的经验,但我读到了它们,我开始想我可以实现责任链模式。比如,每个if-else都可以是链中的一个元素,第6行的这个过滤元素也可以是&#34; Chainable&#34;。
最后它看起来像是:
AbstractChainElement getCheckChain() {
return new CheckAnyExist(
new CheckOneWIthGivenNameExist(
new CheckNoOneWithOtherNameExist(
new FilterOnlyGivenName(
new CheckIsSingleName(
new CheckOtherParameters(
new CheckWithSomeComplicatedLogic()))))));
}
getCheckChain().doChain(persons);
你觉得这样做的好方法还是有更优雅的东西?
有了这个,我可以构建链,用于检查不同的检查类型,使用工厂甚至抽象工厂模式。
类似的东西:
FactoryCheckThesePersonsByTheseParameters implements AbstractFactory {
List<Person> getPersons() {
// get persons with THIS query
}
AbstractChainElement getCheckChain() {
// check persons THIS way
}
}
FactoryCheckThatPersonsByThatParameters implements AbstractFactory {
List<Person> getPersonsBySomeParameters() {
// get persons with THAT query
}
AbstractChainElement getCheckChain() {
// check persons THAT way
}
}
答案 0 :(得分:1)
这不是关于设计模式,而是编码风格和优化。
您可以将条件合并为一个。即 这样:
if (checkAnyPersonExists(persons)) {
if (atLeastOneWithGivenNameExist(persons)) {
if (noOneWithOtherNameExists(persons) {
}
}
}
首先,这似乎是对同一主题/集合进行多次查询。如果您使用它来对数据库进行查询,那么效率会很低。例如,您可以通过在单个查询中组合条件来做得更好。
如果这不是对数据库进行查询,那么您可以直接获取具有给定名称的人数,并根据您可以确定要执行的操作的数量而不是重复查询而略有不同。
另一方面,使用模式并不总是绝对是最佳实践,因为它可能会增加开销。一个简单的If语句,switch-case或带有return的if-not-statement比调用另一个函数/方法更好,因为它更快。
我认为你需要更加具体。
编辑: 例如,如果您有类似于以下内容的内容:
if (i == 1) {
// action 1
} else {
if (i == 2) {
// action 2
} else {
if (i == 3) {
// action 3
} else {
// action 4
}
}
}
您可以使用switch语句
switch (i) {
case 1:
// action 1
break;
case 2:
// action 2
break;
case 3:
// action 3
break;
default:
// action 4
break;
}
另一个例子可能是,如果你有:
if (i == 1) {
// a couple of sentences action
}
else if (x == 2) {
// a couple of sentences action
}
else if (y == 3) {
// a couple of sentences action
}
// no more cope beyond the if statements
这可以重新考虑为:
if (i == 1) {
// a couple of sentences action
return;
}
if (x == 2) {
// a couple of sentences action
return;
}
等等
另一种技巧,例如:
if(name.equals("abc")){
do something
} else if(name.equals("xyz")){
do something different
} else if(name.equals("mno")){
do something different
} ......
.....
else{
error
}
最好使用Map来映射每个字符串(如果它是您验证的有限字符串的有限集合)到特定处理程序。您还可以考虑将一些代码移动到单独的方法
我从SO的几个页面中获取这些示例,因为您看到没有绝对的规则,这取决于代码本身。所以你可以做的就是有一些分析工具可以和你一起使用代码。我认为JetBrain的IntelliJ IDEA是一款出色的IDE,内置酷炫功能。 Eclipse也有一些像这样的功能,但没有那么多。无论如何,这都伴随着练习。
答案 1 :(得分:1)
我会坚持使用if / else语句(虽然我会像asm建议的那样压扁它们)。如果你真的想在这里使用设计模式,那么责任链就可以完成这项任务。另一种选择是使用状态模式。我已经为C#console app提供了示例实现。
public class Person
{
public String Name { get; set; }
public bool IsActive { get; set; }
public Person(String name, bool isActive)
{
this.Name = name;
this.IsActive = isActive;
}
}
public class PersonChecker
{
public PersonCheckerState CurrentState { get; set; }
public String Name { get; private set; }
public bool ShouldBeActive { get; private set; }
public void Check(IEnumerable<Person> persons, string name, bool shouldBeActive)
{
this.Name = name;
this.ShouldBeActive = shouldBeActive;
CurrentState = new InitialState(this);
CurrentState.Check(persons);
}
}
public abstract class PersonCheckerState
{
protected PersonChecker _personChecker;
public PersonCheckerState(PersonChecker personChecker)
{
this._personChecker = personChecker;
}
public abstract void Check(IEnumerable<Person> persons);
}
public class InitialState : PersonCheckerState
{
public InitialState(PersonChecker personChecker) : base(personChecker)
{
}
public override void Check(IEnumerable<Person> persons)
{
if (persons != null && persons.Any())
{
_personChecker.CurrentState = new AnyPersonExistsState(_personChecker);
_personChecker.CurrentState.Check(persons);
}
else
{
Console.WriteLine("No one found");
}
}
}
public class AnyPersonExistsState : PersonCheckerState
{
public AnyPersonExistsState(PersonChecker personChecker) : base(personChecker)
{
}
public override void Check(IEnumerable<Person> persons)
{
if (persons.Any(p => p.Name == _personChecker.Name))
{
_personChecker.CurrentState = new AtLeastOneWithGivenNameExistsState(_personChecker);
_personChecker.CurrentState.Check(persons);
}
else
{
Console.WriteLine("Found person(s), all have different names");
}
}
}
public class AtLeastOneWithGivenNameExistsState : PersonCheckerState
{
public AtLeastOneWithGivenNameExistsState(PersonChecker personChecker) : base(personChecker)
{
}
public override void Check(IEnumerable<Person> persons)
{
if (persons.Any(p => p.Name != _personChecker.Name))
{
Console.WriteLine("Found person(s) with given name, but also some with different name");
}
else // All persons have the same name
{
_personChecker.CurrentState = new NoOneWithOtherNameExistsState(_personChecker);
_personChecker.CurrentState.Check(persons);
}
}
}
public class NoOneWithOtherNameExistsState : PersonCheckerState
{
public NoOneWithOtherNameExistsState(PersonChecker personChecker) : base(personChecker)
{
}
public override void Check(IEnumerable<Person> persons)
{
if (persons.Where(p => p.Name == _personChecker.Name).ToList().Count == 1)
{
_personChecker.CurrentState = new SinglePersonFoundState(_personChecker);
_personChecker.CurrentState.Check(persons);
}
else
{
Console.WriteLine("Found only persons with given name, but more than one");
}
}
}
public class SinglePersonFoundState : PersonCheckerState
{
public SinglePersonFoundState(PersonChecker personChecker) : base(personChecker)
{
}
public override void Check(IEnumerable<Person> persons)
{
Person person = persons.Where(p => p.Name == _personChecker.Name).Single();
if(person.IsActive == _personChecker.ShouldBeActive)
{
Console.WriteLine("Found exactly one person, all OK!!!");
}
else
{
Console.WriteLine("Found exactly one person but parameter IsActive is not OK");
}
}
}
class Program
{
static void Main(string[] args)
{
List<Person> persons = new List<Person>();
persons.Add(new Person("Mike", true));
//persons.Add(new Person("John", true));
PersonChecker personChecker = new PersonChecker();
personChecker.Check(persons, "Mike", true);
Console.ReadLine();
}
}
答案 2 :(得分:0)
您可以应用许多技术来减少嵌套。
下面是几个参考链接。
https://blog.jetbrains.com/idea/2017/08/code-smells-deeply-nested-code/ https://blog.codinghorror.com/flattening-arrow-code/
对于您给出的示例,您可以组合条件,或使用Chain of Responsibility pattern传递列表和谓词,或者使用Command pattern。