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
在我的项目中,我有一个商店 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