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

    万恶的格式!!!

  • 相关阅读:
    一些 SQLite技巧
    linux增加swap空间
    linux解压命令
    数据库常用语句
    服务器命令
    Clickhouse高可用配置总结
    MySQL笔记
    Linux查看硬件信息
    Greenplum安装
    ClickHouse学习笔记
  • 原文地址:https://www.cnblogs.com/cloudffx/p/1767880.html
Copyright © 2011-2022 走看看