在我的项目中,我有一个Store类,我也有一个Manager类。现在经理可以经理许多商店,但商店可以有一个经理。这导致:
经理人课程: ArrayList存储;
商店类别: 经理经理;
我需要能够从商店中引用经理,但我还需要从经理那里获得所有商店。
所以我需要能够做到: manager.getStores(); &安培; store.getManager();
这会创建一个创建新对象实例的循环,并且需要继续从数据库中读取。我不确定如何从设计和实践的角度来看待这个问题,我对此仍然很陌生,所以如果有人能帮助我,那就太棒了!
答案 0 :(得分:0)
对于此示例,我们假设管理器表具有ID
主键,而存储表具有引用管理器manager
的{{1}}字段。
因此ID
来自数据库的SELECT
数据,遍历记录并构建您的managers
对象数组。
来自managers
表的下一个SELECT
,循环遍历这些记录,开始构建您的stores
对象数组,在此循环中,您可以使用嵌套循环来完成管理器数组找到商店对象/记录引用的经理,然后为商店设置该经理,并将商店添加到经理的商店列表中。
stores
答案 1 :(得分:0)
在两个方向上存储引用只有一个原因:性能。除非您需要存储和搜索大量数据,否则请尽可能简单。
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));
}
}
这会自动强制引用完整性,因为商店只能有一个管理器。它将关于商店管理的逻辑封装在商店列表中而不是管理器中。关于这一点的好处是Manager类不需要知道关于商店的任何内容:可以使用相同的类来管理餐馆而不做任何更改。
如果您确实需要getStores
课程中的Manager
,那么您需要实施一些验证:
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();
}
}
}
最后,如果您真的想要在两个方向上维护引用,那么您将需要每次更新以自动更改其他方向的引用。这是一种众所周知的容易出错的方法。一旦你的模型变得复杂,很容易让难以检测的参考腐败蔓延(例如,通过一个子类来覆盖setter而不调用超类的setter)。如果可以,请避免这种情况。
答案 2 :(得分:0)
您可以尝试使用此设计(或根据您的架构的变体)来构建双向映射:
<强> 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