Warning: file_get_contents(/data/phpspider/zhask/data//catemap/9/java/354.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 创建大量类之一的优雅方式_Java_Oop_Design Patterns - Fatal编程技术网

Java 创建大量类之一的优雅方式

Java 创建大量类之一的优雅方式,java,oop,design-patterns,Java,Oop,Design Patterns,在上下文中,我试图使一个游戏类似于口袋妖怪。你可以获得、训练和战斗怪物 每种怪物都是从抽象基类继承而来的类(因此它们可以有独特的行为),希望在整个游戏中会有大量不同的物种。例: abstract class Monster { int hp; void attack(); //Etc. } public class FireBreathingDragon extends Monster { static String species_name = "Fire Breathing

在上下文中,我试图使一个游戏类似于口袋妖怪。你可以获得、训练和战斗怪物

每种怪物都是从抽象基类继承而来的类(因此它们可以有独特的行为),希望在整个游戏中会有大量不同的物种。例:

abstract class Monster {
  int hp;
  void attack();
  //Etc.
}

public class FireBreathingDragon extends Monster {
  static String species_name = "Fire Breathing Dragon";
  //Blah
}
因此,当玩家在探索时,他们会随机遇到某个区域的怪物。然后,游戏需要从生活在该区域的物种列表中随机创建一个怪物。现在,为了使此代码在区域之间可重用(并使在代码中的其他位置动态创建怪物变得容易),我不想将这些可能性硬编码到区域中。相反,我想我想要一个类似于工厂的东西,它可以根据需要创造一个特定物种的怪物,比如:

public class MonsterFactory {
  Monster createMonster(
    String species_name,
    //Possibly other paramters
  );
}
当你有(可能)几十个或数百个不同的怪物类时,问题是如何以“好”或“优雅”的方式实现
createMonster
。当然,您可以使用非常长的
if-else-if-else
switch
语句,但是编写和扩展这些语句非常糟糕。有什么好办法吗?如果在添加更多怪物时相对容易扩展,这也会很好

或者我应该用完全不同的设计来代替


免责声明:我的java有点生疏,语法可能不完美,对此表示抱歉。

您可以在
列表中注册所有
Monster
实现类

List<Class<? extends Monster>> monsterTypes = new LinkedList<>();
monsterTypes.add(FireBreathingDragon.class);
// more

List您可以在
列表中注册所有
Monster
实现类

List<Class<? extends Monster>> monsterTypes = new LinkedList<>();
monsterTypes.add(FireBreathingDragon.class);
// more

List最简单的解决方案是拥有一个数据驱动的monster类。这意味着你只有一个类(或一个小的类),这个类可以用于各种各样具有不同属性和能力的怪物


您可以有一个CSV文件,其中包含每个物种以及该物种的所有属性和能力。这样,您可以通过在电子表格中添加一行来添加一个物种。

最简单的解决方案是使用数据驱动的monster类。这意味着你只有一个类(或一个小的类),这个类可以用于各种各样具有不同属性和能力的怪物


您可以有一个CSV文件,其中包含每个物种以及该物种的所有属性和能力。这样,您可以通过在电子表格中添加一行来添加一个物种。

您可以将所有类放在一个特定的包中,然后扫描该目录中的类文件,加载它们,并跟踪扩展
Monster
的类。您甚至可以定义一些自定义注释来帮助管理此操作,例如,
@IgnoreMonster
在不更改文件位置的情况下临时禁用一些注释。这类似于Hibernate扫描源以查找实体映射的方式

这里有一个例子。所有怪物类都放在package
dload.monsters
中。首先,这里是我在本例中使用的基类:

package dload.monsters;

public abstract class Monster {

    public abstract String getName ();

}
然后是一个
MonsterFactory
,它扫描
dload.monsters
包中的所有类(抱歉,这有点草率,我略过了异常处理):

package dload.monsters;
导入java.io.*;
导入java.net。*;
导入java.util.*;
公营工厂{
私有静态最终列表cls=ClassLoader.getSystemClassLoader().loadClass(“dload.monsters.”+name);
//若怪物和怪物不在同一个包中,你们可以移除
//cls.equals(Monster.class)检查。此检查确保加载
//类扩展了怪物,但不是怪物类本身(因为
//它也在那个包裹里)。
if(Monster.class.isAssignableFrom(cls)&&!cls.equals(Monster.class)){
System.out.println(“Found”+cls.getSimpleName());

monsterClasses.add((Class您可以将所有类放在一个特定的包中,然后扫描该目录中的类文件,加载它们,并跟踪扩展
Monster
的类。您甚至可以定义一些自定义注释来帮助管理这些类,例如
@IgnoreMonster
在不更改文件位置的情况下临时禁用一些类文件。Th类似于Hibernate扫描源以查找实体映射的方式

下面是一个示例。所有怪物类都放在package
dload.monsters
中。首先,这里是我在这个示例中使用的基类:

package dload.monsters;

public abstract class Monster {

    public abstract String getName ();

}
然后是一个
MonsterFactory
,它扫描
dload.monsters
包中的所有类(抱歉,这有点草率,我略过了异常处理):

package dload.monsters;
导入java.io.*;
导入java.net。*;
导入java.util.*;
公营工厂{
私有静态最终列表cls=ClassLoader.getSystemClassLoader().loadClass(“dload.monsters.”+name);
//若怪物和怪物不在同一个包中,你们可以移除
//cls.equals(Monster.class)检查。此检查确保加载
//类扩展了怪物,但不是怪物类本身(因为
//它也在那个包裹里)。
if(Monster.class.isAssignableFrom(cls)&&!cls.equals(Monster.class)){
System.out.println(“Found”+cls.getSimpleName());

monsterClasses.add((Class你应该看看。它将生成每一个产品组合,然后你可以随机选择一个


基本上,该算法将获取属性数组,并创建不同属性的唯一组合,然后将它们添加到一个数组中。然后,当您创建敌人时,您可以从数组中随机选择一个键。这样,每个敌人都有随机机会拥有任意数量的属性。

您应该查看。它将
abstract class base_monster  {
  abstract base_monster factory();
}

/// make sure every monster has a name...
//
abstract class Monster extends base_monster { 
   String name; 
   static int object_counter = 0;

    Monster factory() { 
       name = Integer(object_counter).toString(); 
       object_counter();
       return this; 
    }

    /// this class has a useful setter
    void object_counter( int c ) { object_counter++; out.println( object_counter );    }
}

class Griffon extends Monster {
  Monster factory() { return new Griffon(); }
}


class Harpy extends Monster {
  Harpy() { name = "Grizelda WhuttleThut III"; }
  Harpy factory() { return new Harpy(); }
}


class BlackHarpy  extends Harpy {
  BlackHarpy  factory() { super.factory(); return new BlackHarpy(); }
}


// we assume that each class has a default constructor. But, 
// if the array is filled with monsters of different subclasses we
// would have to use reflection or nasty instanceof switches to be
// able to call a (specific) defined constructor.

ArrayList<Monster> monsters = new ArrayList<Monster>();    

monsters.add( new BlackHarpy() );
for( int I = 0; I < ave_monsters_appearing; I++ )
    monsters.add( new Harpy() );
//
// an array of ten harpies and a boss Harpy.

///
// how can this array of monsters be copied into the other array?
// (we want object copies, not reference copies)
///

ArrayList<Monster> local_monsters = new ArrayList<Monster>();    

/// solution: use the factory method
for( Monster m : monsters ) 
   local_monsters.add( m.factory() ); 
public interface Factory<T> {
    T make();
}
public static class BasicMonster {
}
public static class Monster1 extends BasicMonster {
    public static final Factory<Monster1> getFactory() {
        return new Factory<Monster1>() {
            public Monster1 make() { return new Monster1() ;  }
        };
    }
}
public static class Monster2 extends BasicMonster {
    public static final Factory<Monster2> getFactory() {
        return new Factory<Monster2>() {
            public Monster2 make() { return new Monster2() ;  }
        };
    }
}
List<Factory<? extends BasicMonster>> monsterFactories= new ArrayList<Factory<? extends BasicMonster>>();
{
    monsterFactories.add(Monster1.getFactory());
    monsterFactories.add(Monster2.getFactory());
}
...
BasicMonster newMonster= monsterFactories.get(aRandomOne).make() ;