Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/352.json): failed to open stream: No such file or directory in /data/phpspider/zhask/libs/function.php on line 167

Warning: Invalid argument supplied for foreach() in /data/phpspider/zhask/libs/tag.function.php on line 1116

Notice: Undefined index: in /data/phpspider/zhask/libs/function.php on line 180

Warning: array_chunk() expects parameter 1 to be array, null given in /data/phpspider/zhask/libs/function.php on line 181
Java 如何避免大型if语句和instanceof_Java_Casting_Iteration - Fatal编程技术网

Java 如何避免大型if语句和instanceof

Java 如何避免大型if语句和instanceof,java,casting,iteration,Java,Casting,Iteration,动物 public abstract class Animal { String name; public Animal(String name) { this.name = name; } } public abstract class Animal { String name; public Animal(String name) { this.name = name; } public abstract void exhibitNaturalBehaviou

动物

public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

}
public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

 public abstract void exhibitNaturalBehaviour();

}
import java.util.*;

abstract class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public abstract void accept(AnimalVisitor av);  // <-- Open up for visitors.

}
狮子

public class Lion extends Animal {

 public Lion(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }

 public void roar() {
  System.out.println("Roar");
 }
}
public class Lion extends Animal {

 public Lion(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Roar");
 }
}
鹿

public class Deer extends Animal {

 public Deer(String name) {
  super(name);
 }

 public void runAway() {
  System.out.println("Running...");
 }

}
public class Deer extends Animal {

 public Deer(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Running...");
 }

}
class Lion extends Animal {
    public Lion(String name) {
        super(name);
    }
    public void roar() {
        System.out.println("Roar");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }
}


class Deer extends Animal {

    public Deer(String name) {
        super(name);
    }

    public void runAway() {
        System.out.println("Running...");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }

}
interface AnimalVisitor {
    void visit(Lion l);
    void visit(Deer d);
}

class ActionVisitor implements AnimalVisitor {

    public void visit(Deer d) {
        d.runAway();
    }

    public void visit(Lion l) {
        l.roar();
    }
}
测试动物

public class TestAnimals {
 public static void main(String[] args) {
  Animal lion = new Lion("Geo");
  Animal deer1 = new Deer("D1");
  Animal deer2 = new Deer("D2");

  List<Animal> li = new ArrayList<Animal>();
  li.add(lion);
  li.add(deer1);
  li.add(deer2);
  for (Animal a : li) {
   if (a instanceof Lion) {
    Lion l = (Lion) a;
    l.roar();
   }
   if (a instanceof Deer) {
    Deer l = (Deer) a;
    l.runAway();
   }

  }
 }
}
public class TestAnimals {
 public static void main(String[] args) {

  Animal[] animalArr = {new Lion("Geo"), new Deer("D1"), new Deer("D2")};
  for (Animal a : animalArr) {
     a.exhibitNaturalBehaviour();    
  }

 }
}
public class TestAnimals {
    public static void main(String[] args) {
        Animal lion = new Lion("Geo");
        Animal deer1 = new Deer("D1");
        Animal deer2 = new Deer("D2");

        List<Animal> li = new ArrayList<Animal>();
        li.add(lion);
        li.add(deer1);
        li.add(deer2);
        for (Animal a : li)
            a.accept(new ActionVisitor());         // <-- Accept / visit.
    }
}
公共类测试动物{
公共静态void main(字符串[]args){
动物狮子=新狮子(“Geo”);
动物鹿1=新鹿(“D1”);
动物鹿2=新鹿(“D2”);
List li=new ArrayList();
加上(狮子);
li.添加(deer1);
li.添加(deer2);
对于(动物a:li){
如果(狮子的一个实例){
狮子l=(狮子)a;
l、 吼叫();
}
如果(鹿的实例){
鹿l=(鹿)a;
l、 失控();
}
}
}
}

有没有更好的方法可以在不强制转换的情况下遍历列表?在上述情况下,这似乎没问题,但是如果基类有很多扩展,那么我们也需要很多if块。有没有设计模式或原则来解决这个问题?

是的,在抽象类中提供一个名为
action()
的方法,在两个子类中实现它,一个会咆哮,另一个会失控

如果你的方法不是多态的,你不能没有强制转换。要使其多态,请在基类中声明一个方法,并在子类中重写它。

Animal

public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

}
public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

 public abstract void exhibitNaturalBehaviour();

}
import java.util.*;

abstract class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public abstract void accept(AnimalVisitor av);  // <-- Open up for visitors.

}
狮子

public class Lion extends Animal {

 public Lion(String name) {
  super(name);
  // TODO Auto-generated constructor stub
 }

 public void roar() {
  System.out.println("Roar");
 }
}
public class Lion extends Animal {

 public Lion(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Roar");
 }
}
鹿

public class Deer extends Animal {

 public Deer(String name) {
  super(name);
 }

 public void runAway() {
  System.out.println("Running...");
 }

}
public class Deer extends Animal {

 public Deer(String name) {
  super(name);
 }

 public void exhibitNaturalBehaviour() {
  System.out.println("Running...");
 }

}
class Lion extends Animal {
    public Lion(String name) {
        super(name);
    }
    public void roar() {
        System.out.println("Roar");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }
}


class Deer extends Animal {

    public Deer(String name) {
        super(name);
    }

    public void runAway() {
        System.out.println("Running...");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this);                            // <-- Accept and call visit.
    }

}
interface AnimalVisitor {
    void visit(Lion l);
    void visit(Deer d);
}

class ActionVisitor implements AnimalVisitor {

    public void visit(Deer d) {
        d.runAway();
    }

    public void visit(Lion l) {
        l.roar();
    }
}
测试动物

public class TestAnimals {
 public static void main(String[] args) {
  Animal lion = new Lion("Geo");
  Animal deer1 = new Deer("D1");
  Animal deer2 = new Deer("D2");

  List<Animal> li = new ArrayList<Animal>();
  li.add(lion);
  li.add(deer1);
  li.add(deer2);
  for (Animal a : li) {
   if (a instanceof Lion) {
    Lion l = (Lion) a;
    l.roar();
   }
   if (a instanceof Deer) {
    Deer l = (Deer) a;
    l.runAway();
   }

  }
 }
}
public class TestAnimals {
 public static void main(String[] args) {

  Animal[] animalArr = {new Lion("Geo"), new Deer("D1"), new Deer("D2")};
  for (Animal a : animalArr) {
     a.exhibitNaturalBehaviour();    
  }

 }
}
public class TestAnimals {
    public static void main(String[] args) {
        Animal lion = new Lion("Geo");
        Animal deer1 = new Deer("D1");
        Animal deer2 = new Deer("D2");

        List<Animal> li = new ArrayList<Animal>();
        li.add(lion);
        li.add(deer1);
        li.add(deer2);
        for (Animal a : li)
            a.accept(new ActionVisitor());         // <-- Accept / visit.
    }
}

避免
实例
而不在基类中发明一些新的人工方法(使用非描述性名称,如
performAction
doWhatYouAreSupposedToDo
)的一种优雅方法是使用。以下是一个例子:


动物

public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

}
public abstract class Animal {
 String name;

 public Animal(String name) {
  this.name = name;
 }

 public abstract void exhibitNaturalBehaviour();

}
import java.util.*;

abstract class Animal {
    String name;

    public Animal(String name) {
        this.name = name;
    }

    public abstract void accept(AnimalVisitor av);  // <-- Open up for visitors.

}
测试动物

public class TestAnimals {
 public static void main(String[] args) {
  Animal lion = new Lion("Geo");
  Animal deer1 = new Deer("D1");
  Animal deer2 = new Deer("D2");

  List<Animal> li = new ArrayList<Animal>();
  li.add(lion);
  li.add(deer1);
  li.add(deer2);
  for (Animal a : li) {
   if (a instanceof Lion) {
    Lion l = (Lion) a;
    l.roar();
   }
   if (a instanceof Deer) {
    Deer l = (Deer) a;
    l.runAway();
   }

  }
 }
}
public class TestAnimals {
 public static void main(String[] args) {

  Animal[] animalArr = {new Lion("Geo"), new Deer("D1"), new Deer("D2")};
  for (Animal a : animalArr) {
     a.exhibitNaturalBehaviour();    
  }

 }
}
public class TestAnimals {
    public static void main(String[] args) {
        Animal lion = new Lion("Geo");
        Animal deer1 = new Deer("D1");
        Animal deer2 = new Deer("D2");

        List<Animal> li = new ArrayList<Animal>();
        li.add(lion);
        li.add(deer1);
        li.add(deer2);
        for (Animal a : li)
            a.accept(new ActionVisitor());         // <-- Accept / visit.
    }
}
公共类测试动物{
公共静态void main(字符串[]args){
动物狮子=新狮子(“Geo”);
动物鹿1=新鹿(“D1”);
动物鹿2=新鹿(“D2”);
List li=new ArrayList();
加上(狮子);
li.添加(deer1);
li.添加(deer2);
对于(动物a:li)

a、 accept(new ActionVisitor());//这里有一个动物的
列表。通常,当你有一个对象列表时,所有这些对象都必须能够做同样的事情而不需要浇铸

因此,最好的两种解决方案是:

  • 对于两个具体的类有一个通用的方法(在
    Animal
    中定义为
    abstract
  • 从一开始就将
    狮子
    鹿
    分开,并有两个不同的列表

考虑在构造函数中为动物设置的动作(咆哮、逃跑等)添加一个接口。然后在动物类上有一个抽象方法,如act(),该方法的调用与Adeel类似


这将允许您随时通过字段交换操作。

该语言中的模式匹配支持消除了对丑陋访问者模式的需要

例如,请参见此Scala代码:

abstract class Animal(name: String)

class Lion(name: String) extends Animal(name) {
  def roar() {
    println("Roar!")
  }
}

class Deer(name: String) extends Animal(name) {
  def runAway() {
    println("Running!")
  }
}

object TestAnimals {
  def main(args: Array[String]) {
    val animals = List(new Lion("Geo"), new Deer("D1"), new Deer("D2"))
    for(animal <- animals) animal match {
      case l: Lion => l.roar()
      case d: Deer => d.runAway()
      case _       => ()
    }
  }
}
抽象类动物(名称:String)
类Lion(名称:String)扩展了Animal(名称){
def roar(){
println(“吼!”)
}
}
类鹿(名称:String)扩展了动物(名称){
def失控(){
println(“正在运行!”)
}
}
对象测试动物{
def main(参数:数组[字符串]){
val动物=名单(新狮子(“Geo”)、新鹿(“D1”)、新鹿(“D2”))
(动物l.咆哮)
案例d:鹿=>d.逃跑()
案例u=>()
}
}
}

最简单的方法是让超类实现默认行为

public enum AnimalBehaviour { 
     Deer { public void runAway() { System.out.println("Running..."); } },
     Lion { public void roar() { System.out.println("Roar"); } }
     public void runAway() { } 
     public void roar() { }
 } 

 public class Animal {
     private final String name;
     private final AnimalBehaviour behaviour;
     public Animal(String name, AnimalBehaviour behaviour) {
         this.name = name;
         this.behaviour = behaviour;
     }
     public void runAway() { behaviour.runAway(); } 
     public void roar() { behaviour.roar(); }
  }

 public class TestAnimals { 
   public static void main(String... args) { 
     Animal[] animals = { 
       new Animal("Geo", AnimalBehaviour.Lion), 
       new Animal("Bambi", AnimalBehaviour.Deer), 
       new Animal("D2", AnimalBehaviour.Deer) 
     }; 

     for (Animal a : animals) {
       a.roar(); 
       a.runAway(); 
     } 
   }
 }

事实证明instanceof比上面介绍的visitor模式快;我认为这应该让我们产生疑问,当visitor模式用更多的代码行做同样的事情时,它真的比instanceof更优雅吗

这是我的测试。我比较了3种方法:上面的访问者模式、instanceof和Animal中的显式类型字段

操作系统:Windows 7企业版SP1,64位
处理器:英特尔(R)核心(TM)i7CPU 860@2.80GHz 2.93GHz
内存:8.00GB
JRE:1.7.0_21-b11,32位

import java.util.ArrayList;
import java.util.List;

public class AnimalTest1 {
    public static void main(String[] args) {
        Animal lion = new Lion("Geo");
        Animal deer1 = new Deer("D1");
        Animal deer2 = new Deer("D2");

        List<Animal> li = new ArrayList<Animal>();
        li.add(lion);
        li.add(deer1);
        li.add(deer2);

        int reps = 10000000;

        long start, elapsed;

        start = System.nanoTime();
        for (int i = 0; i < reps; i++) {
            for (Animal a : li)
                a.accept(new ActionVisitor()); // <-- Accept / visit.
        }
        elapsed = System.nanoTime() - start;

        System.out.println("Visitor took " + elapsed + " ns");

        start = System.nanoTime();
        for (int i = 0; i < reps; i++) {
            for (Animal a : li) {
                if (a instanceof Lion) {
                    ((Lion) a).roar();
                } else if (a instanceof Deer) {
                    ((Deer) a).runAway();
                }
            }
        }
        elapsed = System.nanoTime() - start;

        System.out.println("instanceof took " + elapsed + " ns");

        start = System.nanoTime();
        for (int i = 0; i < reps; i++) {
            for (Animal a : li) {
                switch (a.type) {
                case Animal.LION_TYPE:
                    ((Lion) a).roar();
                    break;
                case Animal.DEER_TYPE:
                    ((Deer) a).runAway();
                    break;
                }
            }
        }
        elapsed = System.nanoTime() - start;

        System.out.println("type constant took " + elapsed + " ns");
    }
}

abstract class Animal {
    public static final int LION_TYPE = 0;
    public static final int DEER_TYPE = 1;

    String name;
    public final int type;

    public Animal(String name, int type) {
        this.name = name;
        this.type = type;
    }

    public abstract void accept(AnimalVisitor av); // <-- Open up for visitors.
}

class Lion extends Animal {
    public Lion(String name) {
        super(name, LION_TYPE);
    }

    public void roar() {
        // System.out.println("Roar");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this); // <-- Accept and call visit.
    }
}

class Deer extends Animal {

    public Deer(String name) {
        super(name, DEER_TYPE);
    }

    public void runAway() {
        // System.out.println("Running...");
    }

    public void accept(AnimalVisitor av) {
        av.visit(this); // <-- Accept and call visit.
    }

}

interface AnimalVisitor {
    void visit(Lion l);

    void visit(Deer d);
}

class ActionVisitor implements AnimalVisitor {

    public void visit(Deer d) {
        d.runAway();
    }

    public void visit(Lion l) {
        l.roar();
    }
}
import java.util.ArrayList;
导入java.util.List;
公共类动物测试1{
公共静态void main(字符串[]args){
动物狮子=新狮子(“Geo”);
动物鹿1=新鹿(“D1”);
动物鹿2=新鹿(“D2”);
List li=new ArrayList();
加上(狮子);
li.添加(deer1);
li.添加(deer2);
int reps=10000000;
长时间启动,已过;
start=System.nanoTime();
对于(int i=0;ia、 accept(new ActionVisitor());//方法是否必须有不同的名称(roar、runAway)?多态性的思想是在子类中使用相同的方法,JVM调用适当的方法。有没有更好的方法来做错事?在
测试动物中的代码的意图是什么?是“对每只动物做动物特有的事情”还是“咆哮”
all
Lion
s,
runAway
all
Deer
“没有别的了吗?是的,我倾向于同意。我忍不住投票给访问者。我喜欢它,但我认为你做的比我多。+1关于你后来添加的描述,访问者添加任何新的
动物
都需要修改
动物观察器
。然而,另一个选择是不做这种修改就好了关于。你说呢?@Adeel Ansari,这是一个很好的观点。这取决于我想说的情况。这取决于你是想把具体的动作实现收集在一个类中,还是想把它们分散在不同的类中。在不同的情况下,两者都是可取的。然而,在这种情况下,
roar
runAway
它们是如此的不同,以至于我不想为它们发明一个共同的名称。难道不可能在父类(动物)中实现accept方法吗?不,不幸的是,不可能。这是因为方法签名是在编译时确定的,而目标类型在本例中是确定的