【问题标题】:A pattern for categories of objects with the same data?具有相同数据的对象类别的模式?
【发布时间】:2013-05-20 21:18:06
【问题描述】:

我一直在从事一个项目,遇到了一个关于如何进行设计(面向对象)的令人费解的问题。我有不同类别的对象,例如,EmployeeGroundskeeperCustomer 等具有相同的数据:名称、ID 号等。到目前为止,我已经做了一个单一的接口,@987654324 @,以及每个这些不同的类别extends这个界面。当我尝试检索数据时出现问题。

如果我只想检索其中一个类别的对象,比如Customer,我必须创建一个新方法,getCustomers()。如果我想获得所有员工,我必须创建另一个类似的方法,称为getEmployees()。这对每个类别继续进行。问题是这些方法的实现几乎相同,因为每个类别的数据都是相同的。唯一的区别是每个都只返回一个特定的类别。

有没有更好的方法来做到这一点,我只需要一种方法,我不会重复自己(本着 DRY 的精神)?

注意:这些类别必须分开,因为以后我需要将每个类别放在数据库中自己的表中,因此在某些时候必须分开类别。

可能的解决方案:

我找到了解决此问题的方法,您的建议对找到它有很大帮助(@Adam me)。我没有对每个类别进行单独的方法调用,而是使用了一个泛型方法,其中类别作为泛型参数提供给该方法。此外,类别的类作为数据库表的键提供。

例如,获取特定类别的Person 的签名将是:

public <T extends Person> Queue<T> getPersons (Class<T> key) {...}

如果要调用方法,对于Customer 来说,调用将是:

Queue<Customer> customers = dataStore.<Customer>getPersons(Customer.class);

Class&lt;T&gt; 只是使用了一个键,而在getPersons(...) 方法内部,有一个Map 将类映射到数据库中的一个表(Map&lt;Class&lt;? extends Person&gt;, String&gt;)。因此,当@ 的类提供 987654337@(CustomerEmployee 等),在地图上执行查找,然后从与该类关联的数据库表中检索数据。

虽然它与建议的答案不同,但我非常感谢您的回复:他们引导我找到解决方案的正确方向。

【问题讨论】:

  • 你称它为接口,但你真正的意思是Personabstract class,对吧?关于这些方法,getCustomers()getEmployees(),它们会在哪里(什么类)?
  • 您考虑过基于过滤器的搜索吗?
  • 是的,没错。我的意思是Person是一个抽象类,有方法,getName()getId()等。然后EmployeeCustomer等扩展这个抽象类。一个不同的类具有getCustomers() 等方法,并检索所有客户(比方说从数据库中)。

标签: java database oop design-patterns


【解决方案1】:

您可以使用将您想要返回的类名作为参数的方法。任何继承 Person 的类仍然是 Person 对象,因此您仍然可以这样引用它们。

public Person (String typeOfPerson) {
  return all persons where:      
    person.getClass().getName().equals(typeOfPerson);
}

【讨论】:

  • 这使我朝着正确的方向前进。感谢您的帮助。
【解决方案2】:

您可以通过实现基于过滤器的结构来获取所需的对象。

interface Person { }

class Employee implements Person { }
class Costumer implements Person { }

interface Criteria {
    public boolean match(Person p);
}

class ClassNameCriteria implements Criteria {
    private String className;

    public TypeCriteria(String className) {
        this.className = className;
    }

    public function match(Person p) {
        return person.getClass().getName().equalsIgnoreCase(this.className);
    }
}

class Client {
    private Collection<Person> persons;
    public Collection<Person> getByCriteria(Criteria c) {
        Collection<Person> col = new ArrayList<Person>();
        for(Person p : persons) {
           if (c.match(p)) { 
               col.add(p);
           }
        }
        return col
    }
}

Client client = new Client();
// Adds some persons...
Criteria c = new ClassNameCriteria("Employee");
Collection<Person> = client.getByCriteria(c); // If you need, you can safely cast to Collection<Employee>

【讨论】:

    【解决方案3】:

    可能的解决方案:

    我找到了解决此问题的方法,您的建议对找到它有很大帮助(@Adam me)。我没有对每个类别进行单独的方法调用,而是使用了一个泛型方法,其中类别作为泛型参数提供给该方法。此外,类别的类作为数据库表的键提供。

    例如,获取特定类别的Person 的签名将是:

    public <T extends Person> Queue<T> getPersons (Class<T> key) {...}
    

    调用该方法,对于Customer 来说,调用将是:

    Queue<Customer> customers = dataStore.<Customer>getPersons(Customer.class);
    

    Class&lt;T&gt; 只是使用了一个键,而在getPersons(...) 方法内部,有一个Map 将类映射到数据库中的一个表(Map&lt;Class&lt;? extends Person&gt;, String&gt;)。因此,当@ 的类提供 987654329@(CustomerEmployee 等),在地图上执行查找,然后从与该类关联的数据库表中检索数据。

    虽然它与建议的答案不同,但我非常感谢您的回复:他们引导我找到解决方案的正确方向。

    【讨论】:

      【解决方案4】:

      您可以使用 Bloch 的 Effective java 书中的设计(忘记了哪个项目)。它利用了两个世界,并从两者中汲取了最好的:

      • IPerson:是你想要的getter和setter的接口
      • AbstractPerson 实现 IPerson:被称为 Skeleton 类,并且具有字段和访问器,或者您想要共享的任何代码。
      • 子类(例如您的客户)扩展 AbstractPerson:对您的人员的任何特定添加。

      此解决方案的优点在于您在 Skeleton 类中有一些共享代码,但它们是独立的。一些已经扩展了其他类的新类可以实现该接口,因此也可以成为 IPerson。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 2017-10-07
        • 1970-01-01
        • 2015-09-04
        • 1970-01-01
        • 2018-02-28
        • 2020-03-27
        • 2013-05-12
        相关资源
        最近更新 更多