2016-08-17 2 views
2

У меня есть следующий класс, который представляет собой набор свойств.Альтернатива использованию объекта и литья на карте

public class Properties 
{ 
    /** String type properties. */ 
    private final List<String> m_stringProperties = Arrays.asList("str1", "str2", "str3"); 

    /** Float type properties. */ 
    private final List<String> m_floatProperties = Arrays.asList("float1", "float2", "float3"); 

    /** Integer type properties. */ 
    private final List<String> m_intProperties = Arrays.asList("int1", "int2"); 

    public class PropertyType 
    { 
     private final String m_name; 
     private final Object m_value; 

     public PropertyType(String name, Object value) 
     { 
      m_name = name; 
      m_value = value; 
     } 

     public String getName() 
     { 
      return m_name; 
     } 

     public Object getValue() 
     { 
      return m_value; 
     } 
    } 

    /** The container for the properties. */ 
    private final Map<String, PropertyType> m_properties = new HashMap<>(); 

    public PropertyType getProperty(String name) 
    { 
     return m_properties.get(name); 
    } 

    public void setProperty(String name, Object value) 
    { 
     if ((m_stringProperties.contains(name) && value instanceof String) 
       || (m_floatProperties.contains(name) && value instanceof Float) 
       || (m_intProperties.contains(name) && value instanceof Integer)) 
     { 
      m_properties.put(name, new PropertyType(name, value)); 
     } 

     else 
     { 
      assert false : "Invalid property name"; 
     } 
    } 
} 

Примечания

  1. Каждое свойство имеет имя и значение.
  2. Значения свойств могут иметь тип String, Float или Integer.
  3. Имена свойств ограничены значениями, определенными в списке в верхней части класса.
  4. Данное свойство может быть добавлено только на карту, если оно является правильным типом для этого имени свойства.

Класс может быть использован следующим образом:

Properties properties = new Properties(); 

// set properties 
properties.setProperty("str1", "testId"); 
properties.setProperty("float1", 1.0f); 

// get properties 
Properties.PropertyType str1 = properties.getProperty("str1"); 
Properties.PropertyType float1 = properties.getProperty("float1"); 
Properties.PropertyType invalid = properties.getProperty("unknown"); // return null 

System.out.println("str1: " + str1.getValue()); 
System.out.println("float1: " + float1.getValue()); 

float f1 = (float) properties.getProperty("float1").getValue(); 
Object o1 = properties.getProperty("float1").getValue(); 

System.out.println("f1: " + f1); 
System.out.println("o1: " + o1); 

properties.setProperty("str1", 1.0f);  // assertion - str1 property should be String, not Float 

Я хотел бы знать, если есть лучший способ осуществить это. В частности, я хотел бы избежать использования Object и кастинга, который идет с ним. Я экспериментировал с параметризованными классами и родовыми типами и даже с разнородным гетерогенным контейнером, как описано в пункте 20 Эффективной Java.

Я хотел бы сделать это как можно более типичным - т. Е. Обеспечить контроль типа с помощью компилятора - так, чтобы, если getProperty называется, возвращаемое значение будет автоматически правильным.

Я понимаю, что я мог бы перегрузить setProperty для каждого типа и что getProperty может просто вернуть Object вместо вложенного типа PropertyType но все равно оставит меня с контейнером <String, Object>.

Я новичок Java из C++. В C++ значение карты будет boost::variant.

ответ

0

Чтобы убедиться, что класс получит один из трех типов, и компилятор будет использовать его, вы можете использовать некоторый полиморфизм.

Пример:

public PropertyType(String name, String value) 
     { 
      m_name = name; 
      m_value = value; 
     } 

public PropertyType(String name, Integer value) 
     { 
      m_name = name; 
      m_value = value; 
     } 

public PropertyType(String name, Float value) 
     { 
      m_name = name; 
      m_value = value; 
     } 

Строка, Integer и Float расширяет объект, так что вам не нужно отбрасывать они переменной private final Object m_value;

Но если вам нужно проверить тип переменной в типе исполнения (например, создать и изменить и не знать, является ли это одним из трех типов), это может не сработать.

Смежные вопросы