Инстанцировать одноэлементного объекта, использующего Class.forName ()?

Моя версия, которая включает в себя цепочку, где находится разница, и в чем разница.

function DeepObjectCompare(O1, O2)
{
    try {
        DOC_Val(O1, O2, ['O1->O2', O1, O2]);
        return DOC_Val(O2, O1, ['O2->O1', O1, O2]);
    } catch(e) {
        console.log(e.Chain);
        throw(e);
    }
}
function DOC_Error(Reason, Chain, Val1, Val2)
{
    this.Reason=Reason;
    this.Chain=Chain;
    this.Val1=Val1;
    this.Val2=Val2;
}

function DOC_Val(Val1, Val2, Chain)
{
    function DoThrow(Reason, NewChain) { throw(new DOC_Error(Reason, NewChain!==undefined ? NewChain : Chain, Val1, Val2)); }

    if(typeof(Val1)!==typeof(Val2))
        return DoThrow('Type Mismatch');
    if(Val1===null || Val1===undefined)
        return Val1!==Val2 ? DoThrow('Null/undefined mismatch') : true;
    if(Val1.constructor!==Val2.constructor)
        return DoThrow('Constructor mismatch');
    switch(typeof(Val1))
    {
        case 'object':
            for(var m in Val1)
            {
                if(!Val1.hasOwnProperty(m))
                    continue;
                var CurChain=Chain.concat([m]);
                if(!Val2.hasOwnProperty(m))
                    return DoThrow('Val2 missing property', CurChain);
                DOC_Val(Val1[m], Val2[m], CurChain);
            }
            return true;
        case 'number':
            if(Number.isNaN(Val1))
                return !Number.isNaN(Val2) ? DoThrow('NaN mismatch') : true;
        case 'string':
        case 'boolean':
            return Val1!==Val2 ? DoThrow('Value mismatch') : true;
        case 'function':
            if(Val1.prototype!==Val2.prototype)
                return DoThrow('Prototype mismatch');
            if(Val1!==Val2)
                return DoThrow('Function mismatch');
            return true;
        default:
            return DoThrow('Val1 is unknown type');
    }
}
6
задан javaphild 14 July 2009 в 20:12
поделиться

5 ответов

Классический синглтон также имеет статический метод getInstance () - вызовите его через отражение вместо использования newInstance (). Да, это больше работы, но так оно и есть ...

Или вы могли бы использовать setAccessible () для вызова частного конструктора в любом случае, но вы сломаете синглтон и отправитесь к черту.

В-третьих, вы могли бы вообще отказаться от синглтона и найти лучшее решение (обычно оно есть).

8
ответ дан 8 December 2019 в 12:22
поделиться

Вы можете использовать отражение, чтобы получить ссылку на статический фабричный метод класса, а затем вызвать его. Заводской метод может привести к принудительному применению одноэлементного шаблона

Class c = Class.forName("test.MyClass");
Method factoryMethod = c.getDeclaredMethod("getInstance");
Object singleton = factoryMethod.invoke(null, null);

А затем

public class MyClass {

   private static MyClass instance;

   private MyClass() { 
      // private c'tor 
   }

   public static synchronized MyClass getInstance() {
      if (instance == null) {
         instance = new MyClass();
      }
      return instance:
   }
}

Предупреждение: одноэлементный шаблон проектирования может нанести ущерб вашему здоровью в долгосрочной перспективе.

8
ответ дан 8 December 2019 в 12:22
поделиться

Вы должны знать имя метода вашего одноэлементного класса, который создает объект. Если он, например, называется instance (), вы можете сделать что-то вроде

Class c = Class.forName("MySingleton");
Method m = c.getDeclaredMethod("instance",null);
MySingleton singleton = m.invoke(null,null);
2
ответ дан 8 December 2019 в 12:22
поделиться

Вы можете использовать перечисление и иметь HashMap, названный для каждого из них. Или вы можете использовать некоторую структуру внедрения зависимостей, чтобы получить синглтон чего-то (Guice?)

Edit Хорошо, я тоже перейду к примеру кода:

package tests;
public class EnumSingleton {
    public static void main(String[] args) throws Exception {
        Class<?> c = Class.forName("tests.Singleton1");
        Operation instance = Operation.class.cast(c.getEnumConstants()[0]);
        System.out.println(instance.getTHEAnswer());

        c = Class.forName("tests.Singleton2");
        instance = Operation.class.cast(c.getEnumConstants()[0]);
        System.out.println(instance.getTHEAnswer());
    }
}
interface Operation {
    int getTHEAnswer();
}
enum Singleton1 implements Operation {
    INSTANCE;
    @Override
    public int getTHEAnswer() {
        return 42;
    }
}
enum Singleton2 implements Operation {
    INSTANCE;
    @Override
    public int getTHEAnswer() {
        return 84;
    }
}

И он в целости и сохранности. Править И теперь имеет какое-то значение.

1
ответ дан 8 December 2019 в 12:22
поделиться

. Можете ли вы вместо этого полагаться на существование статического фабричного метода? Он будет полагаться на какое-то соглашение об именах, но это сработает.

Итог: если известно, что класс является одноэлементным, то он должен нести ответственность за эту политику. Следовательно, он должен соответствовать некоторой реализации шаблона, и если вы хотите динамический выбор среди таких классов, вам необходимо иметь возможность предсказать подход «Factory».

0
ответ дан 8 December 2019 в 12:22
поделиться
Другие вопросы по тегам:

Похожие вопросы: