簡體   English   中英

我可以在抽象類中創建一個為實例化類構造實例的方法嗎?

[英]Can I make a method in an abstract class which constructs an instance for the instantiating 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());
     }
 }

嘗試的方法

我曾嘗試使用工廠方法模式,但這不起作用,因為實例是靜態方法,並且不能從靜態方法調用抽象工廠方法。

無法從Models類型靜態引用非靜態方法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;
    }
}

由於其靜態性質和與類型擦除有關的問題,我不認為您可以將所有實例化邏輯都移到父類中,但是您一定可以組織代碼以使其可重用。 我為您編寫了一個簡單的復制/粘貼示例,僅着重於實例化部分,對設計進行了一些更改,因此省略了一些屬性和日志代碼:

接口

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類僅被加載一次。 使BaseModel類中的instance(...)方法受到保護,以明確表明它打算由子級使用,子級可能具有自己的靜態實例屬性。

是的,但是您可能希望將其提取到單獨的類中。

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM