27

我有以下类,我将其用作项目中所有模型的基础:

public abstract class BaseModel
{
    static String table;
    static String idField = "id";       

    public static boolean exists(long id) throws Exception
    {
        Db db = Util.getDb();
        Query q = db.query();
        q.select( idField ).whereLong(idField, id).limit(1).get(table);

        return q.hasResults();
    }

    //snip..
}

然后我尝试通过以下方式扩展它:

public class User extends BaseModel
{
    static String table = "user";
    //snip
}

但是,如果我尝试执行以下操作:

if ( User.exists( 4 ) )
   //do something

然后,它不是查询:"SELECT id FROM user WHERE id = ?",而是生成查询:“SELECT id from null WHERE id = ?”。table因此,类中字段的覆盖User似乎没有任何效果。

我该如何克服呢?如果我setTable()向 BaseModel 添加了一个方法,并setTable()在 的构造函数中调用,那么该类的所有方法也可以使用User新的值吗?tableUser

4

3 回答 3

23

您不能覆盖 Java 中任何类型的静态方法或字段。

public class User extends BaseModel
{
    static String table = "user";
    //snip
}

这将创建一个User#table恰好与 同名的新字段BaseModel#table。大多数 IDE 都会对此发出警告。

如果您更改 BaseModel 中字段的值,它也将应用于所有其他模型类。

一种方法是让基本方法通用

protected static boolean exists(String table, long id) throws Exception
{
    Db db = Util.getDb();
    Query q = db.query();
    q.select( idField ).whereLong(idField, id).limit(1).get(table);

    return q.hasResults();
}

并在子类中使用

public static boolean exists(long id)
{
    return exists("user", id);
}

如果要使用字段方法,则必须创建一个BaseDAO类并有一个UserDAO(每个模型类一个)来相应地设置字段。然后创建所有 daos 的单例实例。

于 2013-10-18T18:58:21.133 回答
10

因为 Java 不允许您覆盖static成员,所以您基本上需要使用稍微冗长但总体上更好的单例模式,其中您仍然在概念上编写“静态”代码,但您在技术上使用 (global/singleton/ "static") 实例,因此您不受static.

(请注意,您还需要使用方法,因为字段不参与多态性,因此不能被覆盖)

public abstract class BaseTable {
    public abstract String table();
    public String idField() { return "id"; }

    public boolean exists(long id) {
        // don't build queries this way in real life though!
        System.out.println("SELECT count(*) FROM " + table() + " WHERE " + idField() + " = " + id);
        return true;
    }
}

public class UserTable extends BaseTable {
    public static final User INSTANCE = new UserTable();
    private UseTabler() {}

    @Override public String table() { return "user"; }
}

public class PostTable extends BaseTable {
    public static final Post INSTANCE = new PostTable();
    private PostTable() {}

    @Override public String table() { return "post"; }
}

public static void main(String[] args) {
    UserTable.INSTANCE.exists(123);
    PostTable.INSTANCE.exists(456);
}

输出:

SELECT count(*) FROM user WHERE id = 123
SELECT count(*) FROM post WHERE id = 456
于 2014-04-05T14:52:41.547 回答
4

为了做你想做的事,不要tableBaseModel. 然后在继承自的其他类中BaseModel,您可以table在默认构造函数中设置任何您想要的。

static {
    table = "user";
}
于 2013-10-18T19:04:31.400 回答