Java类的错误使用 - 最佳实践

3

我相当确定我没有正确处理与类相关的内容。

我使用一个类来创建一组变量(类似于 JavaScript 对象,但并不完全相同)。

以下是我使用它的示例(一个基本示例):

public class myScript {

    public static void main(String[] args) {

        Client   warehouse          = new Client();
        Contacts warehouseContactsA = new Contacts();
        Contacts warehouseContactsB = new Contacts();

        warehouse.idno = 1;
        warehouse.name = "warehouse";
        warehouse.desc = "I don't exist";

        warehouseContactsA.client_idno = 1;
        warehouseContactsA.email       = "emailAAA@place.com"

        warehouseContactsB.client_idno = 1;
        warehouseContactsB.email       = "emailBBB@place.com"            

        insertIntoDB(warehouse,
                     warehouseContactsA,
                     warehouseContactsB);

    }

    public static void insertIntoDB(Client   warehouse,
                                    Contacts warehouseContactsA,
                                    Contacts warehouseContactsB) {

        // code to insert into database here

    }

    private class Client {
        int      idno;
        String   name;
        String   desc;
    }

    private class Contacts {
        int      client_idno;
        String   email;
    }

}

有没有不使用类的理由,如果有,是否有更简单的方法来存储/管理数据而不需要类?


是的,您可以使用更多面向对象的编程范式。 - Blake Yarbrough
你可以将联系人添加到客户端中(例如作为数组),因为联系人始终与客户端相关联。正如@Nathan所提到的,您可能希望在额外的类中声明对象(您可能希望再次使用它们,并且它们与脚本没有强关联)。 - ctst
代码可以并且应该在许多地方进行改进。 - MaxZoom
这个流程是一个基本的例子,真正的程序并不像这样,它只是一个不切实际的演示。 - TheLovelySausage
你可以利用构造函数,因为每当你创建一个新的Client实例时,你想给它一个id、名字和描述。 - ctst
4个回答

2
创建内部类可能会给您带来困扰。如果您没有将它们定义为静态,则需要隐式引用外部类,这对您的代码没有必要,反而会妨碍并导致不明确的错误。也许您这样做是为了只编译一个类并避免使用构建脚本?使用gradle的简单构建脚本非常容易(不像以前我们使用ant那样麻烦),所以这不应该成为问题。最好将持久实体移出到单独的文件中。
您在处理数据库连接和事务方面的做法并不清晰。通常尝试在每个插入操作中使用单独的事务都是不好的,因为每个事务都有开销,并且会增加插入操作运行的时间。通常您会想要批量处理插入操作。
总之,如果您正在编写脚本,请使用脚本语言。Groovy可能是一个不错的选择:
- 您不需要为过程化脚本部分使用外部类。 - 您可以在一个文件中定义多个公共类。 - Groovy包括一个groovy.sql API,可简化JDBC代码。

1
import java.util.Arrays;
import java.util.List;

public final class WarehouseRepository {

    public static void main(String[] args) {

        WarehouseRepository repository = new WarehouseRepository();

        Client warehouse = new Client(1, "warehouse", "I don't exist");
        Contacts warehouseContactsA = new Contacts(1, "emailAAA@place.com");
        Contacts warehouseContactsB = new Contacts(1, "emailBBB@place.com");

        repository.insertIntoDB(warehouse, Arrays.asList(warehouseContactsA, warehouseContactsB));
    }

    public void insertIntoDB(Client warehouse, List<Contacts> contacts) {
        // code to insert into database here
    }
}

final class Client {
    private final int id;
    private final String name;
    private final String desc;

    public Client(int id, String name, String desc) {
        this.id = id;
        this.name = name;
        this.desc = desc;
    }

    public int getId() {
        return id;
    }

    public String getName() {
        return name;
    }

    public String getDesc() {
        return desc;
    }
}

final class Contacts {
    private final int clientName;
    private final String email;

    public Contacts(int clientName, String email) {
        this.clientName = clientName;
        this.email = email;
    }

    public int getClientName() {
        return clientName;
    }

    public String getEmail() {
        return email;
    }
}

需要注意以下几点:

  1. 尽量按照意图和Java规范来命名类。例如,进行数据库操作的类通常被称为repository
  2. 除非必须,否则将类和变量设为final。
  3. 将字段设为私有,如果必须使用,则将它们作为构造函数参数,而不是公共或getter/setter。
  4. 如果一个客户可以关联多个联系人,则将List<Contact>作为客户的字段是一个很好的想法。

0

我会使用 Map<String,String> 来存储属性。其中,我会将字符串和整数存储为字符串,并在需要时解析它们。

希望这有所帮助。


0

是的,那是一个足够好的表示。

不,这并不理想。有几件事情可以改变以改善情况:

可见性选项1:使用访问器使事物私有

您可以通过将“bean”类(即仅具有数据存储目的而没有逻辑的对象)字段设置为私有,并具有公共访问器来掩盖内部表示,从而使事物更符合面向对象的习惯用法:

public class Client {
  private int id;
  public int getId() { return this.id; }
  public void setId(int id) { this.id = id; }
}

可见性选项2:使您的Bean不可变

另一个选项是使您的Bean不可变(这样您就可以在多线程环境中轻松地传递它们),并且保证它们被正确初始化,没有人以非法状态写入它们(例如删除/清零ID但不清除其他数据):

public class Client {
  public final int id;
  public Client(int id) { this.id = id; }
}

最后,如果你有可能存在或不存在的东西(比如描述“我不存在”),我建议使用可选类型,而不是仅仅使用字符串类型。

从可用性的角度来看(以及许多其他面向对象编程的概念),这不是可接受的代码。 - MaxZoom
@MaxZoom 能否详细说明原因? - Diego Martinoia
让我们考虑一个经常发生的真实世界事件:一个客户已经与另一个客户合并。现在它的 idname 已经改变,但是 descriptioncontacts 保持不变。代码将如何处理这种变化? - MaxZoom
这是一个新客户端吗?就像对于任何不可变对象一样? - Diego Martinoia

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