zoukankan      html  css  js  c++  java
  • Object System (对象系统)

      为什么我们需要对象系统?

      你是不是遇到这样的情况,当要保存对象时,通常会有一个基类,类似:
      interface IAchive
      {
       void save(OutputStream out);
       void load(InputStream in);
      }
      然后为每一个需要保存的类写重载save跟load方法,如果当你系统比较庞大时,你就需要为每个类重载一次。
     
      还有我们在做GUI程序的时候,常常要把对象的属性导出到GUI界面查看或者编辑,这时你在初始化你的Property

      界面的时候是不是会为每一个要导出的类写exportToGUIComponent(Component comp)这样的方法呢;

      类似的还有很多,比如要导出接口给脚本等等。
     
      如果我们用上面的方法,那会让这些工作变成枯燥的体力活,那怎么样才能简化这些操作呢?

      这就是Object System存在的理由
      假如我们的对象有这种能力:
      registProperty(String propertyName, Class<?> type, String getterName, String setterName, int usage)
      把对象的属性注册到某个地方,然后要用的时候通过接口把这些要用的对象一次性拿出来,这样我们就需要把属性抽象化
      public interface IMetaProperty {

       int USAGE_SAVE_TO_DB = 1 << 1;
       int USAGE_GUI_BROSWER = 1 << 2;
       int USAGE_SCRIPT_EXPORT = 1 << 3;
       int USAGE_DEFAULT = USAGE_SAVE_TO_DB | USAGE_GUI_BROSWER | USAGE_SCRIPT_EXPORT;
     
       void init(String name, Object owner, Method getter, Method setter, int usage);
     
       void fromStream(PropertyInStream stream) throws Exception;
     
       void toStream(PropertyOutStream stream) throws Exception;
     
       String getName();
     
       String getDesc();
     
       void setDesc(String desc);
     
       Object getValue();
     
       void setValue(Object value);
     
       boolean isWriteable();
     
       boolean isReadable();
     
       int getUsage();
       }
       稍微解释一下,我们通过反射拿到属性的getter和setter以便我们操作属性,usage是指属性的用途,

       比如说:USAGE_SCRIPT_EXPORT说明这个属性是导出到脚本用的。
     
       那我们的属性被注册到什么地方去了呢?我们每个对象都会带有一个叫MetaData的类,该类封装在我们的

       顶级对象MetaObject中,该类存放所有注册进去的属性。也许你觉得一个对象一个MetaData太浪费空间了

       ,static不更好吗?当然,确实很好,这里只是讨论思想,而且由于这种方法在Java中不大好实现(其实也没多想^_^)

       , 在C++的话用个模板就搞定了(像很多c++软件系统自带的RTTI一样),这里只作简单处理
      public class MetaData {

       private Map<String, MetaProperty> propertyList = new HashMap<String, MetaProperty>();
       //...

       public void registerProperty(String name, Class<?> type, Object owner, String getterName, String setterName, int usage)

       public List<MetaProperty> getProperties(int usage)

       public MetaProperty getProperty(String name)
      }
      这样我们就通过getProperties方法把所有属性拿出来,该干什么就干什么,比如要保存对象时只要调用toStream

      方法就可以了,所有属性都一样处理。这是怎么做到的呢,如果自定义的类属性怎么办,PropertyInStream、PropertyOutStream 又是什么?
     
      其实关键是我们在调用registerProperty的时候为每一种Class<?> type生成特定的IMetaProperty,
      我们简单看下registerProperty的实现方法
      public void registerProperty(String name, Class<?> type, Object owner, String getterName,
       String setterName, int usage) throws SecurityException, NoSuchMethodException {
        Method _getter = null != getterName ? owner.getClass().getMethod(getterName) : null;
        Method _setter = null != setterName ? owner.getClass().getMethod(setterName, type) : null;
        IMetaProperty property = MetaDataManager.getInstance().createProperty(type, name, owner, _getter, _setter, usage);
        propertyList.put(name, property);
      }
      前面两行是初始化函数指针,创建实例的是MetaDataManager,MetaDataManager的存在就是帮助我们创建各种各样的IMetaProperty

      ,而且这些IMetaProperty都是可以定制的,这样我们的IMetaProperty就可以交给用户来扩展
      public class MetaDataManager {

       private Map<Class<?>, PropertyCreator> factory = new HashMap<Class<?>, PropertyCreator>();
       private static MetaDataManager instance = new MetaDataManager();

       private MetaDataManager() {
          // int
          registPropertyFactory(int.class, new PropertyCreator() {
           @Override
           public MetaProperty create() {
              return new IntProperty();
           }
          });
          // String
          registPropertyFactory(String.class, new PropertyCreator() {
           @Override
           public MetaProperty create() {
              return new StringProperty();
             }
          });
          //...

        }

       public static MetaDataManager getInstance() {
          return instance;
       }

       public void registPropertyFactory(Class<?> _class, PropertyCreator creator) {
          factory.put(_class, creator);
       }

       public MetaProperty createProperty(Class<?> _class, String name, Object owner, Method getter, Method setter, int usage) {
          if (null == _class || null == name)
             return null;
          PropertyCreator creator = factory.get(_class);
          if (null == creator) {
             throw new RuntimeException("Unsupport property type = " + _class.getName());
          }
          MetaProperty property = creator.create();
          if (null != property) {
             property.init(name, owner, getter, setter, usage);
          }
          return property;
       }
      }
      系统在初始化的时候我们放入了最基本的boolean、int、String等Property,如果我们要定制属性

      ,可以通过registPropertyFactory(Class<?> _class, PropertyCreator creator)把类型跟对象关联起来

      ,就像我们在构造函数里做的那样。
      我们简单看下boolean属性是怎么实现的
      public class BooleanProperty extends CommonProperty {

       @Override
       public void fromStream(PropertyInStream stream) throws Exception {
          setValue(stream.readBoolean().getValue());
       }

       @Override
       public void toStream(PropertyOutStream stream) throws Exception{
          stream.writeBoolean(getName(), (Boolean) getValue());
       }
      }
     
      再来介绍一下PropertyInStream,该接口是我们序列化属性时用的,你可以扩展PropertyInStream为

      BytesArrayInStream、XmlInStream或者时JsonInStream等等各种各样的存储格式
     
      我们看看使用该系统的例子
      class MyBaseObject extends MetaObject {

       private int z;
       boolean flag;
       long time;
       short shortNum;
       float pi;
     
       public MyBaseObject() {
        try {
           registerProperty("z", int.class, "getZ", "setZ", MetaProperty.USAGE_DEFAULT);
           registerProperty("flag", boolean.class, "isFlag", "setFlag", MetaProperty.USAGE_DEFAULT);
           registerProperty("time", long.class, "getTime", "setTime", MetaProperty.USAGE_DEFAULT);
           registerProperty("shortNum", short.class, "getShortNum", "setShortNum", MetaProperty.USAGE_DEFAULT);
           registerProperty("pi", float.class, "getPi", "setPi", MetaProperty.USAGE_DEFAULT);
        } catch (Exception e) {
           e.printStackTrace();
        }
       }

      //...getters && setters
     }
    public class MyObject extends MyBaseObject {

       private int x;
       private int y;
       private String name;
       private byte color;
       private int[] ary;
     
       public MyObject() {
        try {
           registerProperty("x", int.class, "getX", "setX", MetaProperty.USAGE_SAVE_TO_DB);
           registerProperty("y", int.class, "getY", "setY", MetaProperty.USAGE_DEFAULT);
           registerProperty("name", String.class, "getName", "setName", MetaProperty.USAGE_DEFAULT);
           registerProperty("color", byte.class, "getColor", "setColor", MetaProperty.USAGE_DEFAULT);
           registerProperty("ary", int[].class, "getAry", "setAry", MetaProperty.USAGE_DEFAULT);
        } catch (Exception e) {
           e.printStackTrace();
        }
       }
       //...getters && setters
    }
     
    public class Test {
     
       public static void main(String[] args) {
          MyObject obj = new MyObject();
          obj.setX(10000);
          obj.setY(10000);
          obj.setZ(10000);
          obj.setName("Hello");
          obj.setFlag(true);
          obj.setPi(3.1415f);
          obj.setShortNum((short) 277);
          obj.setTime(99999999999L);
          obj.setColor((byte) 127);
          obj.setAry(new int[]{1,2,3,4,5});
          try {
             obj.getMetaData().save(new XmlOutStream(obj.getMetaData().getName(), "c:\\test.xml"));
          } catch (Exception e) {
             e.printStackTrace();
          }
     
       }

    }
    最后我们的MyObject对象被写入一个像下面那样的XML文件中
    <?xml version="1.0" encoding="gb2312"?>
    <MyObject>
      <property name="time" value="99999999999"/>
      <property name="flag" value="true"/>
      <property name="color" value="127"/>
      <property name="shortNum" value="277"/>
      <property name="name" value="Hello"/>
      <property name="ary length" value="5"/>
      <property name="ary[0]" value="1"/>
      <property name="ary[1]" value="2"/>
      <property name="ary[2]" value="3"/>
      <property name="ary[3]" value="4"/>
      <property name="ary[4]" value="5"/>
      <property name="pi" value="3.1415"/>
      <property name="z" value="10000"/>
      <property name="y" value="10000"/>
      <property name="x" value="10000"/>
    </MyObject>

    这样的系统对于数据驱动的系统是非常合适的,而且我觉得在C++中实现会更加优雅一些^_^。

    当然其中还会有很多问题,比如效率等,不过写了这么多实在有点累^_^,下次再说吧。。。

    思路很乱,写得更乱,见谅!O(∩_∩)O

    万恶的格式!!!

  • 相关阅读:
    HDOJ 1846 Brave Game
    并查集模板
    HDU 2102 A计划
    POJ 1426 Find The Multiple
    POJ 3278 Catch That Cow
    POJ 1321 棋盘问题
    CF 999 C.Alphabetic Removals
    CF 999 B. Reversing Encryption
    string的基础用法
    51nod 1267 4个数和为0
  • 原文地址:https://www.cnblogs.com/cloudffx/p/1767880.html
Copyright © 2011-2022 走看看