我可以在抽象 class 中创建一个方法,它为实例化 class 构造一个实例吗?
Can I make a method in an abstract class which constructs an instance for the instantiating class?
我有两个 class 扩展一个抽象模型。两个 class 都实现了一个名为 instance() 的方法,以基本上确保任何时候都只有一个 class 的实例。两个 classes 的 instance() 结构完全相同,所以我认为将它向上移动一个级别到抽象 class 会很好。但是,该方法调用实例化 class' 默认构造函数。是否可以从抽象 class 中调用此构造函数?如果是这样怎么办?还有哪些其他方法可以推广此方法?
简化示例类
我有一个模型的摘要 class,看起来像
public abstract class Models{
public List<Model> models = new ArrayList<Model>();
/** load the different models, with the models with pre-trained model*/
public abstract void load();
}
还有两个像这样的实例化 classes
public class PageLanguageModels extends Models {
/** ensure we only call one of them */
protected static PageLanguageModels _instance = null;
static Logger logger = Logger.getLogger(ProductLanguageModels.class.getName());
public static synchronized PageLanguageModels instance() {
if (_instance == null) {
try {
_instance = new PageLanguageModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
/** load the different models, with the models with pre-trained model*/
@Override
public void load() {
models.clear();
models.add(new BOWModel());
}
}
public class ProductLanguageModels extends Models {
/** ensure we only call one of them */
protected static ProductLanguageModels _instance = null;
static Logger logger = Logger.getLogger(ProductLanguageModels.class.getName());
public static synchronized ProductLanguageModels instance() {
if (_instance == null) {
try {
_instance = new ProductLanguageModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
/** load the different models, with the models with pre-trained model*/
@Override
public void load() {
models.clear();
models.add(new Word2VecModel());
}
}
尝试的方法
我试过使用工厂方法模式,但这不起作用,因为实例是静态方法,不能从静态方法调用抽象工厂方法。
Cannot make a static reference to the non-static method makeModels()
from the type Models
public abstract class Models{
/** load the different models, with the models with pre-trained model*/
public abstract void load();
//Factory method
public abstract Models makeModels();
// Instance code moved up from instanciating classes
protected static Models _instance = null;
static Logger logger = Logger.getLogger(Models.class.getName());
public static synchronized Models instance() {
if (_instance == null) {
try {
_instance = makeModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
}
是的,但您可能希望将其提取到单独的 class。
我认为您不能将所有实例化逻辑移至父级 class,因为它的静态性质和类型擦除方面的问题,但您肯定可以组织代码以使其可重用.我为您写了一个简单的 copy/paste 示例,通过稍微更改您的设计,重点放在实例化部分,所以我省略了一些属性和日志代码:
一个接口
public interface Models {
void load();
}
抽象实现
public abstract class BaseModels implements Models {
protected static <T extends Models> T instance(Class<T> type, T candidate) {
if (candidate == null) {
try {
candidate = type.newInstance();
candidate.load();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return candidate;
}
}
具体实现
public class HeroModels extends BaseModels {
static HeroModels instance;
public static HeroModels instance() {
instance = instance(HeroModels.class, instance);
return instance;
}
@Override
public void load() {
System.out.println("Loading HeroModels...");
}
}
一个简单的测试用例
public class TestDrive {
@Test
public void testEquality() {
HeroModels a1 = HeroModels.instance();
HeroModels a2 = HeroModels.instance();
Assert.assertEquals(a1, a2);
System.out.println("a1: " + a1);
System.out.println("a2: " + a2);
}
}
测试用例输出
Loading HeroModels...
a1: HeroModels@736e9adb
a2: HeroModels@736e9adb
从输出中您可以看到 HeroModels
class 只加载了一次。 BaseModel
class 中的 instance(...)
方法受到保护,以明确它旨在供儿童使用,儿童可能有自己的静态实例属性。
我有两个 class 扩展一个抽象模型。两个 class 都实现了一个名为 instance() 的方法,以基本上确保任何时候都只有一个 class 的实例。两个 classes 的 instance() 结构完全相同,所以我认为将它向上移动一个级别到抽象 class 会很好。但是,该方法调用实例化 class' 默认构造函数。是否可以从抽象 class 中调用此构造函数?如果是这样怎么办?还有哪些其他方法可以推广此方法?
简化示例类
我有一个模型的摘要 class,看起来像
public abstract class Models{
public List<Model> models = new ArrayList<Model>();
/** load the different models, with the models with pre-trained model*/
public abstract void load();
}
还有两个像这样的实例化 classes
public class PageLanguageModels extends Models {
/** ensure we only call one of them */
protected static PageLanguageModels _instance = null;
static Logger logger = Logger.getLogger(ProductLanguageModels.class.getName());
public static synchronized PageLanguageModels instance() {
if (_instance == null) {
try {
_instance = new PageLanguageModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
/** load the different models, with the models with pre-trained model*/
@Override
public void load() {
models.clear();
models.add(new BOWModel());
}
}
public class ProductLanguageModels extends Models {
/** ensure we only call one of them */
protected static ProductLanguageModels _instance = null;
static Logger logger = Logger.getLogger(ProductLanguageModels.class.getName());
public static synchronized ProductLanguageModels instance() {
if (_instance == null) {
try {
_instance = new ProductLanguageModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
/** load the different models, with the models with pre-trained model*/
@Override
public void load() {
models.clear();
models.add(new Word2VecModel());
}
}
尝试的方法
我试过使用工厂方法模式,但这不起作用,因为实例是静态方法,不能从静态方法调用抽象工厂方法。
Cannot make a static reference to the non-static method makeModels() from the type Models
public abstract class Models{
/** load the different models, with the models with pre-trained model*/
public abstract void load();
//Factory method
public abstract Models makeModels();
// Instance code moved up from instanciating classes
protected static Models _instance = null;
static Logger logger = Logger.getLogger(Models.class.getName());
public static synchronized Models instance() {
if (_instance == null) {
try {
_instance = makeModels();
_instance.load();
} catch (Exception e) {
logger.log(Level.SEVERE, "Couldn't load language models.", e);
}
}
return _instance;
}
}
是的,但您可能希望将其提取到单独的 class。
我认为您不能将所有实例化逻辑移至父级 class,因为它的静态性质和类型擦除方面的问题,但您肯定可以组织代码以使其可重用.我为您写了一个简单的 copy/paste 示例,通过稍微更改您的设计,重点放在实例化部分,所以我省略了一些属性和日志代码:
一个接口
public interface Models {
void load();
}
抽象实现
public abstract class BaseModels implements Models {
protected static <T extends Models> T instance(Class<T> type, T candidate) {
if (candidate == null) {
try {
candidate = type.newInstance();
candidate.load();
} catch (InstantiationException | IllegalAccessException e) {
e.printStackTrace();
}
}
return candidate;
}
}
具体实现
public class HeroModels extends BaseModels {
static HeroModels instance;
public static HeroModels instance() {
instance = instance(HeroModels.class, instance);
return instance;
}
@Override
public void load() {
System.out.println("Loading HeroModels...");
}
}
一个简单的测试用例
public class TestDrive {
@Test
public void testEquality() {
HeroModels a1 = HeroModels.instance();
HeroModels a2 = HeroModels.instance();
Assert.assertEquals(a1, a2);
System.out.println("a1: " + a1);
System.out.println("a2: " + a2);
}
}
测试用例输出
Loading HeroModels...
a1: HeroModels@736e9adb
a2: HeroModels@736e9adb
从输出中您可以看到 HeroModels
class 只加载了一次。 BaseModel
class 中的 instance(...)
方法受到保护,以明确它旨在供儿童使用,儿童可能有自己的静态实例属性。