想象一下,您有一个带有菜肴的菜单,每个菜肴应以多种语言提供(法语,英语,阿拉伯语...)。 Dish
类包含具有Language
类型对象的列表。
class Dish {
List<Language> languages
void addLanguage(Language lg){...}
}
class Language { getDescription(){}}
class French extends Language{}
class Menu {List<Dish> dishes }
想要描述该菜的特定语言时,如何避免使用instance of
?
我应该在菜类中为每种语言定义get方法:getFrench(),getArabic(),..吗?
还是应该将其保留在列表中,并通过循环搜索列表来检查法语实例,然后在此getDescription()
上调用list object<language>
?
还是有一种方法可以实现更加多态?
答案 0 :(得分:7)
我认为为每种语言创建一个单独的类不是一个好主意。毕竟,所有这些类都将具有完全相同的方法。
我将使用单个model.pic = System.IO.File.ReadAllBytes(Server.MapPath("~/image/seal.png"));
类,并且在Language
类中,我将保留一个Dish
(我将Map<Locale,Description>
类重命名为以下类)之所以令人困惑,例如Language
,因为它不代表某种语言,因此代表了某种语言的描述。
现在您可以拥有
Description
您的Description getDescription(Locale locale)
类中的方法,它将以传递的Dish
的语言返回对菜肴的描述。
您应该尽可能使用标准的JDK类(例如Locale
而不是自定义类。
考虑了评论并同意其中的一些意见后,我建议将java.util.Locale
移到Map
类中。
Description
您还应该注意,在class Dish
{
Description description = new Description ();
void addDescription(Locale locale, String text)
{
description.addText(locale,text);
}
String getDescription(Locale locale)
{
return description.getText(locale);
}
}
class Description
{
Map<Locale,String> descriptions = new HashMap<>();
public void addText(Locale locale,String text)
{
descriptions.put(locale,text);
}
public void getText(Locale locale)
{
return descriptions.get(locale);
}
}
中搜索特定于语言的描述比在Map
中进行搜索更有效(List
在O(1)
中的查找时间与。HashMap
在O(n)
中的查找时间。
答案 1 :(得分:2)
我认为Language
没有菜单Description
。我将以这种方式进行设计。
class Dish {
List<Description> descriptions;
void addDescription(Description description){...}
Description getDescription(Language language){
// iterate over descriptions and select the appropriate
// or use a Map<Language, Description>
Optional<Description> applicableDescription =
descriptions.stream()
.filter(d -> d.getLanguage().isApplicable(language)).findFirst();
return applicableDescription.orElseGet(this::getDefaultDescription);
}
private Description getDefaultDescription(){
return descriptions.isEmpty() ? null : descriptions.get(0);
}
}
class Description {
Language language;
String shortDescription;
String title;
// and so on...
public boolean isApplicable(Language language){
return this.language.equals(language);
// This logic can be more sophisticated. E.g. If an Italian
// wants to get a menu description, but no italian translation is
// available, it might be useful to choose spanish. But then it
// would be better to return a similarity, like 0.1 to 1.0, instead of true/false.
}
}
class Language {
String name; // like en, de, it, fr, etc. Maybe an enum is better or just using
// java.util.Locale
}
答案 2 :(得分:0)
要提出关于多语言解决方案的另一种方法,我建议看一下ResourceBundle
。它允许根据语言环境获取值。
例如,让我们定义文件:
第一个英语:
data_en.properties
hello=Hello World
对于法语版本:
data_fr.properties
hello=Bonjour le monde
现在,让我们加载资源并打印值:
//Locale.setDefault(Locale.FRENCH);
System.out.println(Locale.getDefault());
ResourceBundle rb = ResourceBundle.getBundle("data");
System.out.println(rb.getString("hello"));
它将打印:
zh_CN
你好世界
如果我取消注释第一行来模拟法语语言环境,则:
fr
Bonjour le monde
这可用于获取不同的翻译。请注意,我从未将其用于数据,仅用于GUI(或固定值),但基于此问题,应该很可能将解决方案改编为使用数据库。
How to load resource bundle messages from DB in Java?
优势?您不必将所有翻译加载到内存中,只需运行该语言环境的翻译即可,因此只需加载真正需要的翻译。