将处理类的所有实例的HashMap的方法放在单独的类中

时间:2018-05-31 06:43:54

标签: java class static static-methods

我有一个创建索引卡的类,在其中,我有一个实例变量,它是一个静态HashMap,用于存储所有创建的实例。

我一直在思考它并且我认为处理对HashMap的操作的方法应该在不同的类中,因为这些方法不能直接在任何索引卡上进行操作,它们会在索引卡列表。

这样,我会有一个IndexCard类和一个ListAdministrator类。这两个类都可以处理不同的函数。

问题是这个新类(ListAdministrator)只有静态方法,因为只有一个列表,没有理由创建任何新的索引卡列表,我只需要一个。

我应该将这些方法移到另一个类还是应该像这样保留?这是一个好习惯吗?

这是代码:

class IndexCard {
    public static HashMap <String, IndexCard> list = new HashMap <> ();
    public String name;
    public String address;
    public String phone;
    public String email;
    public LocalDate dateRegister;

    IndexCard(String name, String dni, String address, String phone, String email) {
        this.name = name;
        this.address = address;
        this.phone = phone;
        this.email = email;
        dateRegister = LocalDate.now();
        if (Utils.validarDni(dni) && !list.containsKey(dni)) {
            list.put(dni, this);
        } else {
            throw new InvalidParameterException ("Error when entering the data or the DNI has already been previously registered");
        }
    }

    /**
     * Update the data of the selected card.
     */
    public void update() throws IllegalAccessException {
        String key = getKeyWithObject(this);
        Scanner reader = new Scanner(System.in);
        Field[] fields = this.getClass().getFields();
        for (Field field: fields) {
            String nameField = Utils.splitCamelCase(field.getName());
            if (!Modifier.isStatic(field.getModifiers()) && (field.getType()).equals(String.class)) {
                System.out.println ("Enter new " + nameField);
                String value = reader.nextLine().trim();
                field.set(this, value);
            }
        }
        reader.close();
        list.put(key, this);
        System.out.println("Updated data \n \n");
    }

    /**
     * Delete the selected card.
     */
    public void delete() throws IllegalAccessException {
        String key = getKeyWithObject(this);
        Field [] fields = this.getClass().getFields();
        for (Field field: fields) {
            if (!Modifier.isStatic(field.getModifiers())) {
                field.set(this, null);
            }
        }
        list.remove(key);
    }

    /**
     * Displays the data of the selected card on screen.
     */
    public void print() throws IllegalAccessException {
        Field [] fields = this.getClass().getFields();
        for (Field field: fields) {
            if (!Modifier.isStatic(field.getModifiers())) {
                String nameFieldConSpaces = Utils.splitCamelCase(field.getName());
                Object value = field.get(this);
                System.out.println(nameFieldConSpaces + ":" + value);
            }
        }
    }

    /**
     * Print all the entries of the desired sublist with the ID, Name and phone number.
     */
    public static <T extends IndexCard> void SubClasslist (Class <T> subClass) {
        for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
            String key = entry.getKey ();
            IndexCard card = entry.getValue ();
            if (card.getClass().equals(subClass)) {
                System.out.println ("ID:" + key + "| Name:" + card.name + "| Phone:" + card.phone);
            }
        }
    }

    /**
     * Returns the object stored in the list of cards when entering the corresponding key.
     */
    public static IndexCard GetObjetWithKey(String key) {
        try {
            return list.get(key);
        } catch (IllegalArgumentException e) {
            System.out.println (e + ": The indicated key does not appear in the database.");
            return null;
        }
    }

    /**
     * Obtain the Key when entering the corresponding card.
     */
    public static String getKeyWithObject (Object obj) {
        for (HashMap.Entry <String, IndexCard> entry: list.entrySet()) {
            if (obj.equals(entry.getValue())) {
                return entry.getKey();
            }
        }
        throw new IllegalArgumentException ("The indicated data does not appear in the database, and therefore we could not obtain the key.");
    }

    /**
     * Returns a list of cards when entering the main data of the card.
     * @param data Corresponds to the identifying name of the file.
     */
    public static ArrayList <IndexCard> SearchByName (String data) {
        try {
            ArrayList <IndexCard> listCards = new ArrayList <> ();
            for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
                IndexCard card = entry.getValue ();
                String name = entry.getValue().name;
                if (name.toLowerCase().trim().contains(data.toLowerCase().trim())) {
                listCards.add(card);
                }
            }
            return listCards;
        } catch (IllegalArgumentException e) {
            System.out.println (e + "The indicated data does not appear in the database, you may have entered it incorrectly.");
            return null;
        }
    }
}

我将把这些静态方法放在新类中。

这是新类ListAdministrator的外观。它甚至不需要构造函数。

class ListAdministrator{
    public static HashMap <String, IndexCard> list = new HashMap <> ();

    /**
     * Print all the entries of the desired sublist with the ID, Name and phone number.
     */
    public static <T extends IndexCard> void SubClasslist (Class <T> subClass) {
        for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
            String key = entry.getKey ();
            IndexCard card = entry.getValue ();
            if (card.getClass().equals(subClass)) {
                System.out.println ("ID:" + key + "| Name:" + card.name + "| Phone:" + card.phone);
            }
        }
    }

    /**
     * Returns the object stored in the list of cards when entering the corresponding key.
     */
    public static IndexCard GetObjetWithKey(String key) {
        try {
            return list.get(key);
        } catch (IllegalArgumentException e) {
            System.out.println (e + ": The indicated key does not appear in the database.");
            return null;
        }
    }

    /**
     * Obtain the Key when entering the corresponding card.
     */
    public static String getKeyWithObject (Object obj) {
        for (HashMap.Entry <String, IndexCard> entry: list.entrySet()) {
            if (obj.equals(entry.getValue())) {
                return entry.getKey();
            }
        }
        throw new IllegalArgumentException ("The indicated data does not appear in the database, and therefore we could not obtain the key.");
    }

    /**
     * Returns a list of cards when entering the main data of the card.
     * @param data Corresponds to the identifying name of the file.
     */
    public static ArrayList <IndexCard> SearchByName (String data) {
        try {
            ArrayList <IndexCard> listCards = new ArrayList <> ();
            for (HashMap.Entry <String, IndexCard> entry: list.entrySet ()) {
                IndexCard card = entry.getValue ();
                String name = entry.getValue().name;
                if (name.toLowerCase().trim().contains(data.toLowerCase().trim())) {
                listCards.add(card);
                }
            }
            return listCards;
        } catch (IllegalArgumentException e) {
            System.out.println (e + "The indicated data does not appear in the database, you may have entered it incorrectly.");
            return null;
        }
    }
}

2 个答案:

答案 0 :(得分:1)

由于单一责任原则,您应该将管理IndexCards和IndexCards本身的问题分开。此外,ListAdministrator应处理所有处理IndexCards管理的事务,以及删除和创建托管对象。

名称ListAdministrator在某种程度上不符合要点,因为它不管理列表,可能使用像IndexCardRegistry这样的东西。

要处理并发性,可以使用ConcurrentMap作为主数据存储。

如果您的IndexCards需要访问它或其他IndexCards,那么让ListAdministrator全部静态可能会派上用场,但这不是最好的设计。他们还需要知道吗?根据我的理解,IndexCards可以是简单的POJO,它只包含数据而根本没有逻辑。

另一方面,使用全静态ListAdministrator,您将来无法同时使用两个托管对象实例,而无需重新编写代码。即使你今天也没想到,一个可以处理任何对象的定义良好的对象注册表可能会在未来的项目中派上用场。因此,我宁愿使用ListAdministrator的实际实例(以及针对它的程序保持灵活性)。

更详细地参考您的评论:

这种方法的想法是将问题清楚地分开,这将使您的代码的未来更改在项目增长时可行(大多数项目倾向于这样做)。我的理解是ListAdministrator应该管理你的IndexCards。在某种程度上,这与对象关系映射器的工作方式相同,但目前您的数据库是HashMap。如果为ListAdministrator创建接口,您甚至可以将HashMap与数据库交换出来,而无需更改其客户端。

在对代码进行第二次调查时,我发现IndexCards不仅存储数据,还有更新数据的方法。这代表了单一责任原则的另一个突破,应予以处理。如果ListAdministrator将为给定的IndexCard提供更新方法,则可以使用您可以想到的许多不同客户端,而无需更改ListAdministrators API背后的任何代码。您的第一个客户端将是您已编程的命令行界面,下一个可能是Web服务。

使用全静态ListAdministrator,您有一个静态类来管理一个静态数据集。它总是只处理IndexCards,你添加的所有东西都会在同一个HashMap中结束(如果允许/兼容)。您可以访问类ListAdministrator的应用程序的每个部分都可以完全访问数据。如果您需要另一个ListAdministrator(处理创建,删除,更新,搜索)不同的类型,您将不得不重构所有内容以适应这一点或开始复制代码。为什么不首先创建基于实例的解决方案。您可以拥有IndexCards的存储库,并可以随意添加新的存储库。

也许这对你的用例来说是过度工程化的,但是为了使责任明确分开,你会发现代码的许多扩展都会正交(不影响现有的代码),这就是真正开始的乐趣所在。如果没有较小的项目,你想如何实践呢?

有关将接口用于灵活代码的原因的更多详细信息(以回应最新评论)

简短的回答是:始终对接口进行编码(如许多文章和Java书中所述)。但为什么呢?

Java接口就像是类及其客户端之间的契约。它定义了一些方法,但本身并没有实现它们。要实现一个接口,您需要使用class XYZ implements SomeInterface定义一个类,并且该类的源代码会执行它认为合理的任何内容来回答接口中定义的方法。您尝试保持接口较小,仅包含基本方法,因为接口越小,必须在需要进行更改时考虑的方法就越少。

Java中常见的习惯用法是为方法定义List<T>返回类型(接口),最有可能是ArrayList(具体类),但可能是{{ 1}}(另一个具体类),或者实现List接口的任何其他东西。通过返回List接口,您可以阻止客户端使用否则返回的具体类的其他方法,这将大大降低您更改&#34; ListProvider&#34;的内部实现的自由度。您隐藏了内部实现,但同意返回满足给定接口的内容。如果您想要承担甚至更少的义务,您可以返回界面LinkedList而不是Iteratable

签出Java API,您会发现像List这样的标准类实现了许多接口。您可以始终在内部使用ArrayList并将其作为可以执行此任务的最小接口返回。

回到你的项目。通过其接口而不是其具体类来引用Registry(ListAdministrator)是至关重要的。界面将定义类似

的方法
ArrayList

它的作用与客户无关,它只是希望一切顺利。因此,如果客户端调用存储库更新方法,它将依赖存储库来更新目标IndexCard。存储库可以根据需要存储数据,在interface IndexCardRegistry { void delete(Long id) throws IllegalAccessException; void update(Long id, Some data) throws IllegalAccessException; // ... } HashMap甚至在数据库中,这对客户来说无关紧要。

List

现在新的迭代,在创建您的注册表时,您将换掉新的

的IndexCardMapBasedRegistry
class IndexCardMapBasedRegistry implements IndexCardRegistry {

    private Map store = new HashMap();

    void delete(Long id) throws IllegalAccessException {
        // code to remove the IndexCard with id from the hashmap 
    }

    void update(Long id, Some data) throws IllegalAccessException {
        // code to get the IndexCard with id from 
        // the hashmap and update its contents 
    }

    // ...

}

class IndexCardDatabaseRegistry implements IndexCardRegistry { private Database db; void delete(Long id) throws IllegalAccessException { // code to remove the IndexCard with id from the database } void update(Long id, Some data) throws IllegalAccessException { // code to update the IndexCard with id in the database } // ... } 变成了 IndexCardRegistry indexCards = new IndexCardMapBasedRegistry();

客户端根本不能更改,但注册表将能够处理一定数量的IndexCards,否则会损坏您的计算机内存。

答案 1 :(得分:1)

继续使用IndexCard类,不需要创建新类ListAdministrator 在类IndexCard中,你有类型hashmap的列表,它在内存数据结构中表示,你在这个类中有n个方法可以在这个数据结构中工作,所以我建议保持单个类,因为它将提供单一责任。

相关问题