Class 1 有 ArrayList<Class2>,但 Class 2 有一个 Class 1 实例?

Class1 has ArrayList<Class2>, but Class2 has a single Class1 instance?

在我的项目中,我有一个商店 class,我还有一个经理 class。现在一个店长可以管理很多店,但是一个店可以有一个店长。这导致:

经理 CLASS 拥有: ArrayList 存储;

商店CLASS有: 经理经理;

我需要能够从商店中引用经理,但我还需要从经理那里获取所有商店。

所以我需要能够做到: manager.getStores(); & store.getManager();

这创建了一个创建新对象实例的循环,并且需要继续从数据库中读取数据。我不确定如何从设计和实践的角度来解决这个问题,我对此还是很陌生,所以如果有人能帮助我,那就太棒了!

对于此示例,我们假设经理 table 具有 ID 主键,并且商店 table 具有引用经理 [=11] 的 manager 字段=].

因此 SELECT 您的 managers 数据库中的数据,遍历记录并构建您的 managers 对象数组。

下一个 SELECT 从你的 stores table,循环遍历这些记录开始构建你的 stores 对象数组,在这个循环中你可以有一个嵌套循环遍历您的经理数组并找到商店 object/record 引用的经理,然后为商店设置该经理,并将该商店添加到经理的商店列表中。

//  Assume db_mgrs and db_stores are result sets return from database.
Object[][] db_mgrs = new Object[][]{{0, "Steve"}, {1, "Bob"}, {2, "Nick"}, {3, "Sam"}};
Object[][] db_stores = new Object[][]{{1, "First Store", 0}, {2, "Second Store", 0}, {3, "Third Store", 2}};

ArrayList<Manager> managers = new ArrayList<>();
ArrayList<Store> stores = new ArrayList<>();

for(int i = 0; i < db_mgrs.length; i++) {
    managers.add(new Manager((int)db_mgrs[i][0], (String)db_mgrs[i][1]));
}

for(int i = 0; i < db_stores.length; i++) {
    stores.add(new Store((int)db_stores[i][0], (String)db_stores[i][1]));
    for(int j = 0; j < managers.size(); j++) {
        if(db_stores[i][2].equals(managers.get(j).getId())) {
            stores.get(i).setMgr(managers.get(j));
            break;
        }
    }
}

for(int i = 0; i < stores.size(); i++) {
    System.out.println(stores.get(i).getMgrName());
}

双向存储引用只有一个原因:为了性能。除非您需要存储和搜索大量数据,否则请尽可能简单。

class Store {
    private Manager manager;

    public Manager hasManager(Manager manager) {
        return this.manager.equals(manager);
    }
}

class StoreList {
    private final List<Store> stores;

    public Stream<Store> getManagedStores(Manager manager) {
        return stores.stream().filter(s -> s.hasManager(manager));
    }
}  

这会自动强制执行参照完整性,因为一个商店只能有一个经理。它将关于商店管理的逻辑封装在商店列表而不是经理中。这样做的好处是,经理 class 根本不需要了解商店的任何信息:相同的 class 可以用于管理餐厅而无需任何更改。

如果您确实需要 Manager class 中的 getStores 那么您将需要实施一些验证:

class StoreList {
    public boolean hasStore(Store store) {
        return stores.contains(store);
    }
}

class Manager {
    private final StoreList stores;

    public boolean hasStoreInStoreList(Store store) {
        return stores.hasStore(store);
    }

    public Stream<Store> getStores() {
        return stores.getManagedStores(this);
    }
}

class Store {
    public void setManager(Manager manager) {
        if (manager.hasStoreInStoreList(this))
            this.manager = manager;
        else
            throw new IllegalArgumentException("Manager for different stores");
    }
}

如果性能是一个问题,那么常见的方法是使用缓存。这是一个很好理解的设计模式,涉及保留搜索结果的副本以避免必须重复搜索。如果引用更改迫使搜索再次成为 运行,则会清除缓存。它可能看起来像这样:

class Manager {
    private Optional<List<Store>> managedStores = Optional.empty();

    public void purgeCache() {
        managedStores = Optional.empty();
    }

    public Stream<Store> getStores() {
        if (!managedStores.isPresent())
            managedStores = Optional.of(stores.getManagedStores(this)
                .collect(Collectors.toList()));
        return managedStores.get().stream();
    }
}

class Store {
    public void setManager(Manager manager) {
        if (!manager.equals(this.manager)) {
            this.manager.purgeCache();
            this.manager = manager;
            this.manager.purgeCache();
        }
    }
}

最后,如果你真的想维护两个方向的引用,那么你需要每次更新都自动更改另一个方向的引用。这是众所周知的容易出错的方法。一旦你的模型变得复杂,就很容易有难以检测的引用损坏蔓延(例如,通过一个 subclass 覆盖 setter 而不调用 superclass 的 setter).如果可以,请避免这种情况。

您可以尝试使用此设计(或根据您的模式对其进行变体)来构建双向映射:

Store.class

public class Store {

    private Manager manager;
    private final String storeName;

    public Store(String storeName) {
        this.storeName = storeName;
    }

    public void setManager(Manager manager) {
        this.manager = manager;
    }

    public Manager getManager() {
        return manager;
    }

    public String getStoreName() {
        return storeName;
    }
}

Manager.class

import java.util.ArrayList;
import java.util.List;

public class Manager {

    private List<Store> stores;
    private final String firstName;
    private final String lastName;

    public Manager(String firstName, String lastName) {
        this.firstName = firstName;
        this.lastName = lastName;
    }

    public String getFirstName() {
        return firstName;
    }

    public String getLastName() {
        return lastName;
    }

    public List<Store> getStores() {
        return stores;
    }

    public void assignStore(Store store) {
        if (stores == null) {
            stores = new ArrayList<>();
        }
        stores.add(store);
    }

    public String getFullName() {
        return firstName + " " + lastName;
    }
}

RetailCorp.class(构建映射):

import java.util.ArrayList;
import java.util.List;

public class RetailCorp {

    public static void main(String[] args) {

        //This is simulating list of managers from a data store
        List<Manager> managerList = getManagerData();

        //This is simulating list of stores from a data store. Each store has a manager assigned to it.
        List<Store> storeList = getStoreData(managerList);

        System.out.println("=== Now, look through each store and assign managers their list of stores");
        for (int i = 0; i < storeList.size(); i++) {
            Store currentStore = storeList.get(i);
            currentStore.getManager().assignStore(currentStore);
        }

        //Output stores and their managers
        showStoresAndTheirManagers(storeList);

        //Output managers and their stores
        showManagersAndTheirStores(managerList);
    }

    private static List<Manager> getManagerData() {
        System.out.println("=== Building manager data");
        List<Manager> managerList = new ArrayList<>();
        int totalManagers = 2;
        for (int i = 0; i < totalManagers; i++) {
            managerList.add(new Manager("FN-" + i, "LN-" + i));
        }
        return managerList;
    }

    private static List<Store> getStoreData(List<Manager> managerList) {
        System.out.println("=== Building stores data");
        List<Store> storeList = new ArrayList<>();
        int totalStores = 3;
        for (int i = 0; i < totalStores; i++) {
            storeList.add(new Store("Store " + i));
        }
        storeList.get(0).setManager(managerList.get(0));    //store 0 -> manager 0
        storeList.get(1).setManager(managerList.get(1));    //store 1 -> manager 1
        storeList.get(2).setManager(managerList.get(0));    //store 2 -> manager 0
        return storeList;
    }

    private static void showStoresAndTheirManagers(List<Store> storeList) {
        System.out.println("=== Print stores and their manager");
        for (int i = 0; i < storeList.size(); i++) {
            Store currentStore = storeList.get(i);
            System.out.println(currentStore.getStoreName() + " has Manager: " + currentStore.getManager().getFullName());
        }
    }

    private static void showManagersAndTheirStores(List<Manager> managerList) {
        System.out.println("=== Print managers and their stores");
        for (int i = 0; i < managerList.size(); i++) {
            Manager currentManager = managerList.get(i);
            System.out.println("Manager: " + currentManager.getFullName() + " has total " + currentManager.getStores().size() + " stores");
            currentManager.getStores().forEach(s -> System.out.println(s.getStoreName()));
        }
    }
}

运行输出

=== Building manager data
=== Building stores data
=== Now, look through each store and assign managers their list of stores
=== Print stores and their manager
Store 0 has Manager: FN-0 LN-0
Store 1 has Manager: FN-1 LN-1
Store 2 has Manager: FN-0 LN-0
=== Print managers and their stores
Manager: FN-0 LN-0 has total 2 stores
Store 0
Store 2
Manager: FN-1 LN-1 has total 1 stores
Store 1