Java覆盖静态方法

4

我发现自己需要覆盖一个静态方法,因为这是最合理的,但我知道这是不可能的。

超类Entity.java:

abstract public class Entity<T> {
    public Entity() {
        //set up database connection
    }

    abstract public static Map<Object, T> getAll();

    abstract public void insert();

    abstract public void update();

    protected void getData(final String query) {
        //get data via database
    }

    protected void executeQuery(final String query) {
        //execute sql query on database
    }
}

其中一个具体实现是Account.java:

public class Account extends Entity<Account> {
    private final static String ALL_QUERY = "SELECT * FROM accounts";
    private final static String INSERT_QUERY = "INSERT INTO accounts (username, password) VALUES(?, ?)";
    private final static String UPDATE_QUERY = "UPDATE accounts SET password=? WHERE username=?";

    private String username;
    private String password;

    public Account(final String username, final String password) {
        this.username = username;
        this.password =  password;
    }

    public String getUsername() {
        return username;
    }

    public void setUsername(final String username) {
        this.username = username;
    }

    public String getPassword() {
        return password;
    }

    public void setPassword(final String password) {
        this.password = password;
    }

    @Override
    public static Map<Object, Account> getAll() {
        //return a map using the ALL_QUERY string, calls getData(string);
    }

    @Override
    public void insert() {
        //insert this using INSERT_QUERY, calls executeQuery(string);
    }

    @Override
    public void update() {
        //update this using UPDATE_QUERY, calls executeQuery(string);
    }
}

我并没有详细解释代码,但是对它的任何一般反馈也将不胜感激,希望注释足够说明问题。

基本上,我认为我们都可以同意使用Account.getAll()比使用new Account().getAll()更有意义(如果我要为其引入一个虚拟语法)。 然而,我确实想让它扩展Entity类,目前仅出于方便考虑,但以后我可能需要使用Entity的集合/列表/多重集,并对它们执行update()操作,例如,如果我要构建一个每分钟执行所有更新的队列。

所以,有没有一种正确构造getAll()的方法呢?

敬礼。


只需在静态方法上删除@Override,就可以了。另请参见:https://dev59.com/cEbRa4cB1Zd3GeqP1ZDf - Matt Ball
感谢您使用我的建议。不将您使用的答案标记为正确,可能会引起其他人对您原始问题的关注。 - christopher
@MattBall 从实现角度来看,确实很好。但我更喜欢一些更严格的限制,这也是我首先在接口中提到它的原因。@ChrisCooney 可能有一些延迟,因为我已经将其标记为正确。我希望我已经正确地使用了您的建议,特别是使用了通用参数“Entity<T>”。 - skiwi
3
阅读马丁·福勒(Martin Fowler)的表数据网关和数据映射器模式。您还应该了解数据访问对象。从您的POJO中删除持久性数据。 - Sotirios Delimanolis
我有点担心你的数据库设计。最佳实践是创建一个类来模拟数据库表中的数据,然后将其作为数据库访问对象(DAO)的重要组成部分。DAO的重要作用是将数据访问和应用程序处理数据的关注点分离。这是你正在使用的设计模式吗? - scottb
显示剩余3条评论
2个回答

1
你可以为所有元素的操作创建单独的类:
abstract public class Collection<T extends Entity<T>> {
    abstract public static List<T> getAll();
    public void printAll() {
        // Print all entries of List obtained from getAll()
    }
}

你可以将它用作:
public class Accounts extends Collection<Account> {
    @Override
    public List<Account> getAll() {
        //return a list using the ALL_QUERY string, calls getData(string);
    }
}

它不是一个集合,而是一个数据访问对象/服务。或者,如下面的答案所称,它是一个存储库。使用、API和功能与Java或其他集合非常不同。 - Thomas W
我只是因为没有更好的名字而称它为“Collection”,一个不会干扰现有集合类的名称确实会更好。 - ValarDohaeris

1

我觉得这并不是因为“最合理”的原因。

将持久性绑定在实体上并不是一个好主意。已经有很多模式可以解决这个问题并提供适当的设计。

例如,在领域驱动设计中,人们试图实现“持久性无关”。考虑为每个实体创建一个仓库:

interface Repository<T> {
    List<T> findAll();
    void insert(T);
    void update(T);
}

所以您可以通过任何方式覆盖它:
interface UserRepository extends Repository<User> {
    // some other methods which is meaningful for User
    User findByLoginName(String loginName);
}


class UserRepositoryImpl implements UserRepository {
    List<User> findAll() {
         // call whatever query
    }
    void insert(T){...}
    void update(T){...}
    User findByLoginName(String loginName) {...}
}

通过合适的设计和处理实体检索/存储的组件,您可以拥有一个更少耦合的实体,并且使用能够执行适当“覆盖”的仓库。


我非常喜欢“Repository”这个命名(感谢Adrian!)。我会点赞这个答案,但总的来说,我建议使用_Hibernate_而不是花费两年时间编写持久层。如果你试图自己动手做,会有很多问题和陷阱。 - Thomas W
@ThomasW 你知道吗?很多人在实现仓储时都在使用Hibernate :) 还有,看看Spring Data - Hibernate,它让创建仓储变得轻而易举 :) Hibernate很容易使用,但这并不意味着可以用持久化逻辑(使用Hibernate)来污染实体 - Adrian Shum

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接