我有一种方法,根据类型send作为此方法的参数来实例化特定类。这很有效,但我真的不喜欢这种if(c == class_name.class)
方式来解决这个问题,而且我非常确定有更好的方法可以使用泛型和继承来实现这一点。我使用的方法看起来(可能是错误的......)对我来说很脏。
我遵循了几个关于泛型和继承的教程,但即使我认为我或多或少地分别理解这两个概念,我仍然要理解两者的混合......我认为这两个概念都可以解决我的问题混合。任何人都可以告诉我正确的跟踪,泛型,继承,两者或保持我的代码这样。有更好的方法吗?
这是我的实际方法:
private void addData(String csvFile, char separator, Class<?> c) {
int lineNumber = 1;
CSVReader reader;
try {
reader = new CSVReader(new InputStreamReader(getAssets().open(csvFile)), separator);
String[] line;
realm.beginTransaction();
if(c == FlagDef.class) {
while ((line = reader.readNext()) != null) {
FlagDef flagDef = new FlagDef(Long.parseLong(line[0]), line[1], line[2]);
Log.d(TAG, String.format("%s %s %s", line[0], line[1], line[2]));
realm.copyToRealm(flagDef);
lineNumber++;
}
}
if(c == Picture.class) {
while ((line = reader.readNext()) != null) {
Picture picture = new Picture(Long.parseLong(line[0]), line[1]);
Log.d(TAG, String.format("%s %s", line[0], line[1]));
realm.copyToRealm(picture);
lineNumber++;
}
}
realm.commitTransaction();
reader.close();
} catch (FileNotFoundException ex) {
Log.e(TAG, String.format("File %s not found : %s", csvFile, ex));
} catch (IOException ex) {
Log.e(TAG, String.format("Error parsing line number %s : %s", lineNumber, ex));
}
}
对此方法的调用:
addData(FILE_FLAGS,SEPARATOR,FlagDef.class);
addData(FILE_PICTURES,SEPARATOR,Picture.class);
可以找到copyToRealm
方法的声明here
这适用于Android,我实际上是针对API 16。
为简洁起见,我仅指出两种类型Picture
和FlagDef
,但我计划至少有10种不同的类型。
答案 0 :(得分:2)
有类型擦除的概念,在运行时,泛型将被删除。你现在拥有的东西被认为是“干净的”,并且在这种情况下使用了很多。
我唯一能建议的是让你的task me(type: GradleBuild){
buildFile 'mybuild.gradle' //defaults to build.gradle so not needed
dir 'someDir'
tasks 'clean', 'build'
}
和Picture
可以实现标记界面,例如FlagDef
(是的,名字非常糟糕),并将您的方法更改为:
CSVable
以便在编译时过滤您的类型(您只能传递实现<T extends CSV> void addData(Class<T> c)
的对象)
答案 1 :(得分:2)
将Class<?> c
参数更改为Function<String[], RealmModel>
:
private void addData(String csvFile, char separator, Function<String[], RealmModel> modelConstructor) {
而不是所有if
块,你可以只有一个:
while ((line = reader.readNext()) != null) {
RealmModel model = modelConstructor.apply(line);
Log.d(TAG, String.join(" ", line));
realm.copyToRealm(model);
lineNumber++;
}
对addData方法的调用如下所示:
addData(FILE_FLAGS, SEPARATOR, line -> new FlagDef(Long.parseLong(line[0]), line[1], line[2]));
addData(FILE_PICTURES, SEPARATOR, line -> new Picture(Long.parseLong(line[0]), line[1]));
答案 2 :(得分:1)
您可以创建一个构建器类,该类将创建一个读取行的对象:
abstract class Builder<T> {
abstract T build( String[] line);
}
有2个实现:
class FlagDefBuilder extends Builder<FlagDef > {
@Override
FlagDef build( String[] line )
{
FlagDef flagDef = new FlagDef(Long.parseLong(line[0]), line[1], line[2]);
Log.d(TAG, String.format("%s %s %s", line[0], line[1], line[2]));
return flagDef;
}
}
class PictureBuilder extends Builder<FlagDef > {
@Override
FlagDef build( String[] line )
{
Picture picture = new Picture(Long.parseLong(line[0]), line[1]);
Log.d(TAG, String.format("%s %s", line[0], line[1]));
return picture;
}
}
然后addData将是这样的:
private void addData(String csvFile, char separator, Builder<?> b) {
int lineNumber = 1;
CSVReader reader;
try {
reader = new CSVReader(new InputStreamReader(getAssets().open(csvFile)), separator);
String[] line;
realm.beginTransaction();
while ((line = reader.readNext()) != null) {
realm.copyToRealm(b.build(line));
lineNumber++;
}
}
realm.commitTransaction();
reader.close();
} catch (FileNotFoundException ex) {
Log.e(TAG, String.format("File %s not found : %s", csvFile, ex));
} catch (IOException ex) {
Log.e(TAG, String.format("Error parsing line number %s : %s", lineNumber, ex));
}
}
你可以这样调用它:
addData(FILE_FLAGS,SEPARATOR, new FlagDefBuilder());
addData(FILE_PICTURES,SEPARATOR, new PictureBuilder());
您可以在不修改addData的情况下添加第三种构建器类型。
答案 3 :(得分:1)
我对我的问题有几个答案。
我认为@VGR的解决方案很好。但问题是我的项目是针对Android API 16.所以在我的情况下,由@ Function was only introduced since API 24无法使用@VGR提出的功能解决方案。因此,这种解决方案可能缺乏未来发展的灵活性。无论如何,功能编程并不是我现在最难以判断的最佳技能。
StephaneM提出的解决方案是一个很好的解决方案,但是我得到它需要修改,不能一概而论。
@Eugene和@mickaël-b在评论中建议使用Strategy Design Pattern。这是我最终选择的解决方案。谢谢大家的回答和评论,这非常有帮助:)请参阅下面的工作代码,如果我能以任何方式改进它,请随时发表评论。或者如果我犯了一些错误......我再次使用2个课程,因此这里有两个简洁的策略,但最后我会有十多个策略。
对于那些感兴趣的人,这段代码可用于从csv文件生成Realm数据库。
RealmDbGenerator dbGenerator = new RealmDbGenerator(this);
//flags
dbGenerator.setGenerationStrategy(new FlagDefStrategy());
dbGenerator.addData(FILE_FLAGS,SEPARATOR);
//pictures
dbGenerator.setGenerationStrategy(new PictureStrategy());
dbGenerator.addData(FILE_PICTURES,SEPARATOR);
RealDbGenerator:
public class RealmDbGenerator {
private static final String TAG = RealmDbGenerator.class.getSimpleName();
public void setGenerationStrategy(GenerationStrategy generationStrategy) {
this.generationStrategy = generationStrategy;
}
private GenerationStrategy generationStrategy;
private Realm realm;
private Context context;
public RealmDbGenerator(Context context) {
this.realm = Realm.getDefaultInstance();
this.context = context;
}
public void addData(String csvFile, char separator) {
CSVReader reader;
int lineNumber = 1;
try {
reader = new CSVReader(new InputStreamReader(context.getAssets().open(csvFile)), separator);
String[] line;
realm.beginTransaction();
while ((line = reader.readNext()) != null) {
generationStrategy.addData(line, realm);
}
realm.commitTransaction();
reader.close();
} catch (FileNotFoundException ex) {
Log.e(TAG, String.format("File %s not found : %s", csvFile, ex));
} catch (IOException ex) {
Log.e(TAG, String.format("Error parsing line number %s : %s", lineNumber, ex));
}
}
}
策略界面:
public interface GenerationStrategy {
void addData(String[] line, Realm realm);
}
FlagDefStrategy:
public class FlagDefStrategy implements GenerationStrategy {
private static final String TAG = FlagDefStrategy.class.getSimpleName();
@Override
public void addData(String[] line, Realm realm) {
FlagDef flagDef = new FlagDef(Long.parseLong(line[0]), line[1], line[2]);
Log.d(TAG, String.format("%s %s %s", line[0], line[1], line[2]));
realm.copyToRealm(flagDef);
}
}
PictureStrategy:
public class PictureStrategy implements GenerationStrategy {
private static final String TAG = FlagDefStrategy.class.getSimpleName();
@Override
public void addData(String[] line, Realm realm) {
Picture picture = new Picture(Long.parseLong(line[0]), line[1]);
Log.d(TAG, String.format("%s %s", line[0], line[1]));
realm.copyToRealm(picture);
}
}
答案 4 :(得分:0)
我认为这是一个模块化问题,为什么不创建两种添加数据的方法并避免使用类类型参数?
private void addFlagData(String csvFile, char separator) {
...
}
private void addPictureData(String csvFile, char separator) {
...
}