【问题标题】:How to implement reading default object settings from a database with oop and soc如何使用 oop 和 soc 从数据库中读取默认对象设置
【发布时间】:2011-07-06 16:31:30
【问题描述】:

我有一个如下所示的课程:

public class Location {
    private int id;
    private String name = "noname";
    ... // other properties

    public Location(int locationId) {
        this.id = locationId;
        this.name = getNameFromDatabase(locationId);
    } 

    public static Map<Integer,Location> getAllLocations() {
        // reads all locations from database and puts objects into a map
    }       

    ... // other methods

}

name 属性可以通过以下方式之一定义:

  1. 开发者在源码中定义的默认值
  2. 在数据库中定义的默认应用值(覆盖开发者的默认值),
  3. 在数据库中定义的位置特定值(覆盖之前的两个值)

在应用程序中,位置对象由Map&lt;Integer,Location&gt; locations = Location.getAllLocations(); 实例化

实现 1. 和 3. 很简单,但是实现 2.“应用程序特定默认值”的最合适方式是什么

  • 我可以在 getNameFromDatabase 方法中获取默认值,但是我正在为每个新位置在数据库中寻找一个默认值(因为它是默认值,所以应该只选择一次)

  • 在位置对象实例化中,我可以预先将默认值读取到一个特殊的位置对象中,然后将该对象传递给构造函数(但我相信我会破坏关注点分离)

  • 我相信我需要在类中实例化的静态单例,但我不知道如何实现它

    编辑

  • 显示的 name 属性只是整个类的一个 sn-p(大约有 20 个属性)

  • 默认应用值也存储在数据库中;实际上它与其他位置在同一个表中,除了它有一个特殊的 id -1;所以我目前在 getNameFromDatabase 方法中所做的是select * from location where location_id in (-1, &amp;lt;locationid&amp;gt;) order by location_id,但我确实认为这是一个糟糕的设计,因为我正在读取我设置的每个位置的默认位置值

  • 所以我正在寻找的是:在方法 getnamefromdatabase 中,它首先检查是否有为我的位置 ID 定义的名称。如果没有,检查我是否已经有一个 globaly 定义的 defaultlocationname,如果没有,在数据库中找到它然后定义全局 defaultlocationname。

【问题讨论】:

    标签: java oop design-patterns separation-of-concerns


    【解决方案1】:

    如果您适当地定义了getNameFromDatabasegetApplicationDefaultName 方法,则应该执行以下操作。 (还应该定义一个 setApplicationDefaultName 方法来为给定 locationId 设置应用程序的名称)

    private int id;
    private String name =- "noname"; // default in source code?
    
    public Location(int locationId) {
        // ...
        String appName = Location.getApplicationDefaultName();
        String dbName = getNameFromDatabase(locationId);
        if(dbName != null) {
            this.name = dbName;
        } else if (appName != null) {
            this.name = appName;
        } // else name will default to initially set value.
    }
    

    当您使用语句this.name = getNameFromDatabase(locationId) 分配名称时,您将覆盖先前分配给this.name 的值,因此您的案例1 将不会实现。您分配名称的逻辑(或任何具有您的第 1、2 和 3 点描述的预期行为的属性)的逻辑应该是:

    if (db has specific name)
        use db specific name              // point 3
    else if (db has default name)         // point 2
        use db default name
    else
        don't overwrite source code name  //point 1
    

    编辑

    将检索默认数据库值与检索该值的做法(每个 VM 一次,或每次,或有时取决于月相)分开的一种方法是使用 @987654321 @ 设计模式。接口RetrievalMethod 应该有一个方法getDefaultFromDatabase(),其行为可以由实现者指定。这样做,您的 Location 的 getApplicationDefaultName 方法(以及 RetrievalMethod 策略设置方法)将如下所示:

    private RetrievalMethod myLocationRetriever = GenericRetrievalMethod(/*...*/);
    // ...
    public void setLocationRetrievalMethod(RetrievalMethod retr) {
        myLocationRetriever = retr;
    }
    // ... 
    private String getApplicationDefaultName() {
        myLocationRetriever.getDefaultFromDatabase();
    }
    

    根据您的应用程序规范,您可以将myLocationRetriever 设置为适当的行为。

    【讨论】:

    • 对不起,我澄清了我的问题,getapplicationdefaultname() 还从数据库中读取它的值(从与 getnamefromdatabase 相同的表中读取,除了默认位置设置有一个特殊的 id -1)。
    • 正如您在编辑中所述,每次检查数据库中是否存在特定于位置的名称时,您都会从数据库中获取默认名称。缓存一次调用的结果以查看数据库中是否存在特定于应用程序的名称,然后仅查询特定于位置的名称(如果存在),如果不存在则恢复到缓存,最后恢复如果以上都不起作用,则开发定义默认值。但是查询任何数据的开销可能会抵消您从 DB 中选择额外的可能行所产生的任何开销
    • 好的,但是(db has default name)总是检查数据库,我想要的问题是,如何避免每次创建新对象时检查数据库。它会第一次检查,创建对所有其他对象可见的新默认对象,所以下一次,我将只从内部对象中读取数据。但我知道如何通过在外部创建默认对象来实现这一点,这会破坏 SoC
    • @zeldi,我用一种使用策略模式保持 SoC 的方法编辑了我的问题。
    猜你喜欢
    • 2012-02-25
    • 2017-02-18
    • 2016-04-25
    • 1970-01-01
    • 2015-02-20
    • 2014-07-15
    • 1970-01-01
    • 1970-01-01
    • 2012-03-01
    相关资源
    最近更新 更多