我可以在构造实例化类的实例的抽象类中创建一个方法吗?

时间:2015-12-02 20:04:26

标签: java constructor abstract-class

我有两个扩展抽象模型的类。这两个类都实现了一个名为instance()的方法,基本上确保了任何时候只有一个类的实例。 instance()的结构对于这两个类完全相同,所以我认为将它提升到抽象类是很好的。但是,该方法调用实例化类'默认构造函数。是否可以从抽象类中调用此构造函数?如果是这样的话?还有哪些其他方法可用于推广这种方法?

简化示例类

我有一个类似于

的模型的抽象类
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();
}

还有两个类似于此的实时课程

 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());
     }
 }

尝试方法

我尝试使用工厂方法模式,但这不起作用,因为实例是静态方法,并且无法从静态方法调用抽象工厂方法。

  

无法对非静态方法makeModels()进行静态引用   来自型号

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;
    }
}

2 个答案:

答案 0 :(得分:2)

我不认为您可以将所有实例化逻辑移动到父类,因为它具有静态特性和类型擦除问题,但您肯定可以组织代码以使其可重用。我通过专注于实例化部分更改您的设计,为您编写了一个简单的复制/粘贴示例,因此我遗漏了一些属性并记录了代码:

界面

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类只加载了一次。 instance(...)类中的BaseModel方法受到保护,以明确它旨在供子级使用,子级可能具有自己的静态实例属性。

答案 1 :(得分:-1)

是的,但您可能希望将其提取到单独的类中。