This discussion is archived
1 2 Previous Next 25 Replies Latest reply: Oct 20, 2010 2:59 PM by 796367 RSS

decide the really class instance used in runtime

800928 Newbie
Currently Being Moderated
Hi:
I have to query something form the db, and then wrap the query result as a Object,and I have several types of querying, so I tried to extract them using the extend mechanism.

----------------------------------
abstract class AbstractExecutor {
     public String     sql;
     public abstract String execut();
}
class UserExecutor extends AbstractExecutor {
     @Override
     public String execut() {
          ArrayList<User> resList = new ArrayList<User>();
          sql = "select username from user";
          // user the sql to query from db
          ResultSet rs = null;//
          // iterative the rs, make each record to a User object and put it to the
          // list:someting like that:
          User u = new User("This argument coms from the db");
          resList.add(u);
          // build the result string by the resList, here I just call its toString
          // method for example.
          return resList.toString();
     }
     static class User {
          String     name;
          public User(String name) {this.name = name;}
     }
}
class MessageExecutor extends AbstractExecutor {
     @Override
     public String execut() {
          ArrayList<Message> resList = new ArrayList<Message>();
          sql = "select title from message";
          // use the sql to query from db
          ResultSet rs = null;//
          // iterative the rs, make each record to a Message object and put it to
          // the list:someting like that:
          Message u = new Message("This argument coms from the db");
          resList.add(u);
          // build the result string by the resList, here I just call its toString
          // method for example.
          return resList.toString();
     }

     static class Message {
          String     title;
          public Message(String title) {this.title = title;}
     }

}

public class Client {
     public static void main(String[] args) {
          Map<String, AbstractExecutor> map = new HashMap<String, AbstractExecutor>();
          map.put("1", new UserExecutor());
          map.put("2", new MessageExecutor());

          // get the parameter from request...
          int type = 2;
          map.get(type + "").execut();
     }
}
--------------------------------------

Obviously the steps of the two bussiness logic(the UserExecutor and the MessageExecutor) are so same with other,the only difference is the 'sql', and the 'class' used to wraped the result(the User and the Message),
so I wonder I can extract the same logic to their superclass(the AbstractExecutor)?

I have tried the Generics:
--------------------------------------
abstract class AbstractExecutor<E> {
     public String     queryFields[]={};
     public String execut(){
          ArrayList<E> resList = new ArrayList<E>();
          sql = "select "+queryFields[0]+" from "+queryFields[1];
          // use the sql to query from db
          ResultSet rs = null;//
          // iterative the rs, make each record to a E object and put it to
          // the list,someting like that:
          E e = ? // here how to make a instance of E(a User object or a Message object)?
          resList.add(e);
          // build the result string by the resList, here I just call its toString
          // method for example.
          return resList.toString();
     }
}
If the above work,the UserExecutor can be like this:
class UserExecutor extends AbstractExecutor<User> {
     //just override the fields of its superclass.
     queryFields={"username","user"};
}
class User{
          String     name;
          public Message(String name) {this.name = name;}
}
I wonder if this is possible? If the Generics can not make it work, is there any other ways to do this?
What I really want to is reducing the repetitive codes and making it extendable,since I may add other executor in the future.
  • 1. Re: decide the really class instance used in runtime
    jduprez Pro
    Currently Being Moderated
    Your example is oversimplified in that the "client" business logic (ArrayList.toString()) doesn't depends on the type of the objects contained in the list.
    With that in mind...
    I wonder if this is possible?
    Yes, just replace the question mark with a call to an abstract method (note: that highlights the GoF pattern Template Method):
    abstract class AbstractExecutor<E> {
        <E> protected abstract E createInstanceOfContent(ResultSet rs);
    
        public String execut(){
          ArrayList<E> resList = new ArrayList<E>();
          sql = "select "+queryFields[0]+" from "+queryFields[1];
          // use the sql to query from db
          ResultSet rs = null;//
          // iterative the rs, make each record to a E object and put it to
          // the list,someting like that:
          E e = createInstanceOfContent(rs);
          resList.add(e);
          // build the result string by the resList, here I just call its toString
    }
    
    class UserExecutor extends AbstractExecutor<User> {
          protected User createInstanceOfContent(ResultSet rs) {
            User user = new User();
            user.setName(...);
            return user;
        }
    }
    is there any other ways to do this?
    Your abstract executor doesn't really leverage generics type-safety, so you might do that with plain inheritance:
    abstract class AbstractExecutor{
        protected abstract Object createInstanceOfContent(ResultSet rs);
    
        public String execute(){
          ArrayList resList = new ArrayList();
          sql = "select "+queryFields[0]+" from "+queryFields[1];
          // use the sql to query from db
          ResultSet rs = null;//
          // iterative the rs, make each record to a E object and put it to
          // the list,someting like that:
          E e = createInstanceOfContent(rs);
          resList.add(e);
          // build the result string by the resList, here I just call its toString
    }
    
    class UserExecutor extends AbstractExecutor {
          protected Object createInstanceOfContent(ResultSet rs) {
            User user = new User();
            user.setName(...);
            return user;
        }
    }
    What I really want to is reducing the repetitive codes and making it extendable, since I may add other executor in the future.
    Good intention. Try to identify which operations are common to all executor types (for example, creation of some entity, storage in some collection, iteration over the collection,...), and ask yourself whether they leverage any common interface of the entities manipulated (your example doesn't show that).

    For your information, Spring's "JDBC" or "DAO" API, I don't remember the name, has templatized this kind of logic for a while now. Even if you don't use Spring as a Dependency Injection framework, the spring-jdbc library is worth a look.
  • 2. Re: decide the really class instance used in runtime
    800928 Newbie
    Currently Being Moderated
    Thanks for reply.
    jduprez wrote:
    Your example is oversimplified in that the "client" business logic (ArrayList.toString()) doesn't depends on the type of the objects contained in the list.
    With that in mind...
    Eh, yes it is a little oversimplified. Since I am afraid too much codes may scared pepole.

    In fact,the superclass should get the sql query required parameter for example the 'table name', the 'field name',also the most imporment-- the Class used to wrap the result from the db.
    >
    >
    Your abstract executor doesn't really leverage generics type-safety, so you might do that with plain inheritance:
    abstract class AbstractExecutor{
    protected abstract Object createInstanceOfContent(ResultSet rs);
    
    public String execute(){
    ArrayList resList = new ArrayList();
    sql = "select "+queryFields[0]+" from "+queryFields[1];
    // use the sql to query from db
    ResultSet rs = null;//
    // iterative the rs, make each record to a E object and put it to
    // the list,someting like that:
    E e = createInstanceOfContent(rs);
    resList.add(e);
    // build the result string by the resList, here I just call its toString
    }
    
    class UserExecutor extends AbstractExecutor {
    protected Object createInstanceOfContent(ResultSet rs) {
    User user = new User();
    user.setName(...);
    return user;
    }
    }
    Fine!! I am so fucking stupid!! Thanks, this manner is rather clear!!! You are a good guy!!
    >
    What I really want to is reducing the repetitive codes and making it extendable, since I may add other executor in the future.
    Good intention. Try to identify which operations are common to all executor types (for example, creation of some entity, storage in some collection, iteration over the collection,...), and ask yourself whether they leverage any common interface of the entities manipulated (your example doesn't show that).

    For your information, Spring's "JDBC" or "DAO" API, I don't remember the name, has templatized this kind of logic for a while now. Even if you don't use Spring as a Dependency Injection framework, the spring-jdbc library is worth a look.
    Sure, I will have a look at these docs as possible. Thank you again.
  • 3. Re: decide the really class instance used in runtime
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    apachemaven wrote:
    Hi:
    I have to query something form the db, and then wrap the query result as a Object,and I have several types of querying, so I tried to extract them using the extend mechanism.
    Why?

    Most database work is specifically driven by business needs.
    The fact that this might result in many similar types of functionality doesn't alter that.
    The simple solution to making it "easier" (and less prone to bugs) to create code like this is to learn how to use existing DB frameworks, existing code generators or just create your own code generator. Attempting generic abstract interfaces to achieve the same thing is unlikely to be a good idea as it ignores exceptional cases and the abstraction layers make it harder to figure out bugs when they do occur (which can be said about existing DB frameworks as well but bugs in there are much less likely than rolling it oneself.)
  • 4. Re: decide the really class instance used in runtime
    800928 Newbie
    Currently Being Moderated
    The simple solution to making it "easier" (and less prone to bugs) to create code like this is to learn how to use existing DB frameworks, existing code generators or just create your own code generator.
    Yes, existing framework works fine,but we have to consider the Invasive and Learning Curve.
    The spring-jdbc is weight, the mybatis should config the sql words manually.
    Also, for our application,we just save the tomcat log to the database(one log item to a record in db),then query the related information according to the user request,for exapmle, query the Independent IP, browser and platform and etc.

    In most case,client send a time range,the server will start to query.
    for example:
    select count(dinstinct ip) from log where time between xxx and xxx group by ip.

    Our app is not very complex,so we decide to use the native jdbc.

    However if one know some light jdbc framework has little invasivation, please let me know, I will have a try.
    THanks.
  • 5. Re: decide the really class instance used in runtime
    jduprez Pro
    Currently Being Moderated
    Yes, existing framework works fine,but we have to consider the Invasive and Learning Curve.
    The spring-jdbc is weight
    I suspect you didn't mean lightweight? :o)
    However if one know some light jdbc framework has little invasivation, please let me know, I will have a try.
    Our app is not very complex,so we decide to use the native jdbc.
    Well, I'd say the JDBC API is invasive anyway.
    Regardless of the complexity of the app's logic, the main differences between a framework and the raw JDBC API are:
    - the maintenability of the code, in particular the robustness against changes in the DB layout and in the code's BL: regardless of any framework, the DAO pattern helps shield BL code from the persistence. I just find Spring to be handy (and not heavy nor overly invasive) to implement DAOs
    - the level of error-cases handling. One generally underestimates how tedious and bug-prone it is to handle those damn SQLExceptions that can surge anywhere in JDBC APIs
  • 6. Re: decide the really class instance used in runtime
    796367 Explorer
    Currently Being Moderated
    jschell wrote:
    apachemaven wrote:
    I have to query something form the db, and then wrap the query result as a Object,and I have several types of querying, so I tried to extract them using the extend mechanism.
    Why?
    Indeed, why?
    ... The simple solution to making it "easier" (and less prone to bugs)...
    Again, I agree. However, I have a slightly different tilt on the matter. I do in fact work on a rather sophisticated DB with 18 tables -- some with just a few records, and others with thousands (and growing). I have taken the most "popular" SQL commands and encapsulated them into a class file for each of the DB TABLES. For example let's say we have a customer TABLE with these fields...
    TABLE customer {
      cutomer_id
      customer_name
    }
    ... Now I make a class definition. Note: my code is in PHP, but it's close enough to a JAVA to get the idea...
    public class Customer
    {
      protected $id;
      protected $name;
     
      public Customer($id, $name){
        $this.id = $id;
        $this.name = $name;
      }
     
      public static function db_customer_by_id($dbc, $id){
        // SQL query here...
        return new Customer($row[0], $row[1]);
      }
      
      public function save($dbc){
        // insert, update, delete
      }
     
      protected function insert($dbc){
        // SQL query here...
      }
    
      protected function update($dbc){
        // SQL query here...
      }
    
      protected function delete($dbc){
        // SQL query here...
      } 
    }
    ... Notice that:
    - The most COMMON sql queries are encapsulated into the class file.
    - The SQL query to get information from the database is <tt>static</tt> and returns a whole Customer instance.
    - The <tt>insert(), update(), and delete()</tt> methods are <tt>protected</tt> so you cannot call them with outside code -- making it even easier to deal with these objects. Instead call the single <tt>public save()</tt> method.

    Now with a class file that has all the most common queries, using it in a program is super easy. Note, again my code is PHP, but should translate easily over to JAVA...
    // put the main SQL QUERY here...
    $query = "SELECT customer_id WHERE customer_name LIKE 'A%'";
    $result = mysqli_query($dbc, $query);
    while($row = mysqli_fetch_array($result, MYSQLI_NUM))
    {
      $customer = Customer::db_customer_by_id($dbc, $row[0]);
      // do something with $customer
      $customer->save($dbc);
    }
    The point is -- now you can grab complete objects out of the DB, work on them as objects, then save them as objects. easy as pie.

    IMPORTANT: The main SQL QUERY only returns <tt>customer_id</tt> values... DO NOT use SELECT *.
  • 7. Re: decide the really class instance used in runtime
    800928 Newbie
    Currently Being Moderated
    Thanks, I will have a try.
  • 8. Re: decide the really class instance used in runtime
    796367 Explorer
    Currently Being Moderated
    apachemaven wrote:
    Thanks, I will have a try.
    There's one more trick to this kind of set up that you should be aware of. As you know, when getting information from the database, all the data is already there, so the <tt>static db_customer_by_id()</tt> will work as usual and return a fully initialized <tt>Customer</tt> object. The concern is how does the <tt>Customer</tt> class know when to insert, update or delete? Here's a brief clue, in the <tt>save()</tt> method.
    public void save($dbc){
      if(id == 0) {
        insert($dbc);
      }
      else
      {
        update($dbc);
      }
    }
    So now at runtime, when you create a new Customer from scratch, that is, do not access data from the DB, just do this:
    Customer c = new Customer(0, "John Doe");
    c->save($dbc);
    Note: this is not the end all story to this strategy because I have not included the <tt>delete()</tt> in the <tt>save()</tt> method above -- because it requires a bit more practice to pull off easily. But this is enough to let you know that there are good ways of encapsulating many common SQL Queries right into a JAVA class file. To me, this is the EASIEST way to handle the majority of the SQL that you write.
  • 9. Re: decide the really class instance used in runtime
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    apachemaven wrote:
    The simple solution to making it "easier" (and less prone to bugs) to create code like this is to learn how to use existing DB frameworks, existing code generators or just create your own code generator.
    Yes, existing framework works fine,but we have to consider the Invasive and Learning Curve.
    The spring-jdbc is weight, the mybatis should config the sql words manually.
    Also, for our application,we just save the tomcat log to the database(one log item to a record in db),then query the related information according to the user request,for exapmle, query the Independent IP, browser and platform and etc.
    If you have a complex application leading to a complex database layer then the learning curve is large regardless.

    Conversely a small database layer means that you should implement it directly rather than attempting to wrap it in layers.
    Our app is not very complex,so we decide to use the native jdbc.
    I don't see that. I don't see any way to read the he classes you posted except as an abstraction layer. (Abstract in this sense meaning attempting to abstract away jdbc rather than just implementing a database layer.)
  • 10. Re: decide the really class instance used in runtime
    jschellSomeoneStoleMyAlias Expert
    Currently Being Moderated
    pierrot_2 wrote:
    ... The simple solution to making it "easier" (and less prone to bugs)...
    Again, I agree. However, I have a slightly different tilt on the matter. I do in fact work on a rather sophisticated DB with 18 tables -- some with just a few records, and others with thousands (and growing). I have taken the most "popular" SQL commands and encapsulated them into a class file for each of the DB TABLES. For example let's say we have a customer TABLE with these fields...
    Far as I can see you have described a database layer.

    Not an abstraction layer.

    The only difference between your solution and mine would be that I would have generated the code that you wrote.
  • 11. Re: decide the really class instance used in runtime
    796440 Guru
    Currently Being Moderated
    pierrot_2 wrote:
    Again, I agree. However, I have a slightly different tilt on the matter. I do in fact work on a rather sophisticated DB with 18 tables -- some with just a few records, and others with thousands (and growing).
    18 tables and thousands of rows is minuscule.
    $query = "SELECT customer_id WHERE customer_name LIKE 'A%'";
    Bad idea. You should use PreparedStatement.
  • 12. Re: decide the really class instance used in runtime
    796440 Guru
    Currently Being Moderated
    pierrot_2 wrote:
    apachemaven wrote:
    Thanks, I will have a try.
    There's one more trick to this kind of set up that you should be aware of. As you know, when getting information from the database, all the data is already there, so the <tt>static db_customer_by_id()</tt> will work as usual and return a fully initialized <tt>Customer</tt> object. The concern is how does the <tt>Customer</tt> class know when to insert, update or delete? Here's a brief clue, in the <tt>save()</tt> method.
    public void save($dbc){
    if(id == 0) {
    insert($dbc);
    }
    else
    {
    update($dbc);
    }
    }
    That's a rather fragile approach.
  • 13. Re: decide the really class instance used in runtime
    796367 Explorer
    Currently Being Moderated
    jverd wrote:
    That's a rather fragile approach.
    I gotta admit that not very many people are using this DB, and it is not available for the public to use. So far so good in my case. And in my real application I have a<tt> static db_available() </tt> which scans the DB for any FLAGGED items that can be over written. Therefore, in my app I never use:
    Customer c = new Customer(0, "");
    Instead I use...
    Customer c = Customer::db_available();
    .. which returns a Customer object with the<tt> id </tt> set with the next available row that can be overwritten -- otherwise it will be set to 0.
    jschell wrote:
    Far as I can see you have described a database layer.

    Not an abstraction layer.

    The only difference between your solution and mine would be that I would have generated the code that you wrote.
    My implementation is much more complex than the simplified version I gave here, and there are other properties in the actual classes that I did not outline here -- for example, most of my classes hold an<tt> int flags </tt>where I use a bitmask to extract the state of that object -- which would have made it nearly impossible for a code generator to predict how that information should be interpreted. Some of the classes have other classes inside them, even though the data is held in another DB TABLE. Some of the TABLES are also intermediary which join several classes and TABLE data together -- each with their own<tt> int flags </tt>value.

    In an attempt to make my code and DB easy to maintain, I just made the database layer consistent throughout each class. So far so good in my case... as I cannot wait for an improved version of the language to come along, or hope that someone will provide a proper generator for my app. It really wasn't that hard to write anyway, and it's even easier to maintain.

    The hard part is wrapping your head around it all!
  • 14. Re: decide the really class instance used in runtime
    796367 Explorer
    Currently Being Moderated
    jverd wrote:
    18 tables and thousands of rows is minuscule.
    This because of the way I handle the data in the DB. First, I never delete rows, I recycle them. Each one of my classes has an<tt> int flags </tt> which I dedicate the first bit as a flag for delete. Instead of calling a DELETE, I update that bit to 1. This has saved my neck numerous times, because I have a good chance to recover it. An added benefit is that the numbers of rows never grows past a maximum capacity. For example, a TABLE named<tt> reminder </tt> contains data that does not need to persist past the expiration date. My<tt> static db_available() </tt> in that class scans the DB for expired or FLAGGED reminders and reuses that row.
    $query = "SELECT customer_id WHERE customer_name LIKE 'A%'";
    Bad idea. You should use PreparedStatement.
    Not neccessary with my technique, because that query only returns a list of ID numbers, then I use a loop to create the desired object array with the already static SQL Query written into the class file.
1 2 Previous Next

Legend

  • Correct Answers - 10 points
  • Helpful Answers - 5 points