英文:
Generic type container in Java
问题
假设我想在Java中创建一个通用类型的容器,使用如下接口:
public interface GenericDataContainer<T>
我希望实现这个接口的类能够有一个底层结构来保存类型为 T
的数据。然而,我还想要追踪添加数据的人。在 GenericDataContainer
接口中,添加对象到容器的方法可能会声明如下:
public void put(String added_by, T obj);
我刚开始学习泛型,还有Java,所以我不确定最好的做法是什么。
假设我有一个结构,比如一个 HashMap
,用来追踪我拥有的用户,假设我通过他们的 name
字符串来识别用户。我怎样将我容器中的 T
对象与添加它的用户的 String
关联起来?
我是不是应该将对象包装到一个包装类中,该类有两个成员:
T obj;
String added_by;
还是有更好的方法?
假设我还想允许某些用户访问对象,而不仅仅是所有者;我能否向这样的包装对象中添加一个 String
数组,以跟踪被授予访问权限的用户?
整个接口规范如下(请不要对此提出批评:我无法控制规范):
public interface SecureDataContainer<T> {
public void createUser(String id, String passw);
// 根据所有者统计添加的元素数量
public int getSize(String owner, String passw);
public boolean put(String owner, String passw, T data);
public T get(String owner, String passw, T data);
public T remove(String owner, String passw, T data);
public void copy(String owner, String passw, T data);
// 允许其他用户访问对象
public void share(String owner, String passw, String other, T data);
public Iterator<T> getIterator(String owner, String passw);
}
英文:
Let's say I want to create a generic type container in Java, using an interface like this:
public interface GenericDataContainer<T>
I want classes that'll implement this interface to have an underlying structure to hold data of type T
. However, I also want to keep track of who a piece of data was added by. In the GenericDataContainer
interface, a method to add an object to the container might have a declaration like this:
public void put(String added_by, T obj);
I am just getting started with generics, and also Java in general, so I'm not sure what the best way to go about this would be.
Let's say I have a structure, like a HashMap
that keeps track of what users I have, and let's say I identify users by their name
String
. How would I go about associating a T
object inside my container to the String
of the user who added it?
Would I wrap the object into a wrapper class that has two members:
T obj;
String added_by;
or is there a better way?
Let's say I also want to be able to allow certain users to access the object, not just the owner; could I just add an array of String
s to such wrapper object to keep track of users who were granted access?
This is what the whole interface specification is like (please don't critique it: I have no control over the specification)
public interface SecureDataContainer<T>{
public void createUser(String id, String passw);
// number of elements added by owner
public int getSize(String owner, String passw);
public boolean put(String owner, String passw, T data);
public T get(String owner, String passw, T data);
public T remove(String owner, String passw, T data);
public void copy(String owner, String passw, T data);
// enable another user to access the object
public void share(String owner, String passw, String other, T data);
public Iterator<T>getIterator(String owner, String passw);
}
答案1
得分: 2
你提出的内容很有道理,你可以这样做:
public class OwnedData<T> {
private final OwnerId owner;
private final T data;
// 构造函数接受 owner/data … 或许还有 getter 方法
}
(注意:更合理的做法是有一个专门的类型来表示所有者,你可能有两个不同的用户名为“Carl”的用户,所以最好不要仅依赖于字符串名称来标识所有者)
但是没错,这将是一种处理方法。当然,然后你需要考虑如何正确实现该类的 equals()
和 hashCode()
方法,以确保对象可以被清楚地区分。
然而,在现实世界中,事情当然要复杂得多。权限模型很复杂。你不仅需要考虑用户,还需要考虑“角色”。或者用户组。或者一些数据是只读的,一些数据是可读/可写的。
换句话说:权限系统可能需要满足许多不同的要求。因此,我们无法告诉你什么是“最适合你的”,因为这里没有人知道你的具体要求!
英文:
What you outlined makes sense, you could do something like:
public class OwnedData<T> {
private final OwnerId owner;
private final T data;
// constructor taking owner/data ... getters maybe
}
(Note: it makes more sense to have a distinct type that denotes Owners, you might have two different users named "Carl", so better prepare yourself to be not rely just on a String name to identify owners)
But yes, that would be one way to go about this. Of course, you then have to think to correctly implement equals()
and hashCode()
for that class, to ensure that objects can be clearly distinguished.
Yet, in the real world, things are of course much more complicated. Permission models are complicated. You have to think not only about users, but also about "roles". Or groups of users. Or some data being read-only, some data being read/writeable.
In other words: there are many different requirements that a permission system might have to fulfil. Therefore we can't tell you what is best for you, as nobody here knows your specific requirements!
答案2
得分: 0
Sure, here's the translated content:
假设我有一个结构,类似于一个HashMap,用于跟踪我拥有的用户,假设我通过他们的名字字符串来标识用户。我该如何将T对象与添加它的用户的字符串关联起来呢?
以下是代码部分:
import java.util.HashMap;
import java.util.Map;
interface GenericDataContainer<T> {
public void put(String added_by, T obj);
}
class HashMapBasedContainer<T> implements GenericDataContainer<T> {
// 如果此部分位于其他地方,请确保可以从此处访问
Map<String, T> mapper = new HashMap<>();
@Override
public void put(String added_by, T obj) {
this.mapper.put(added_by, obj);
}
}
假设我还想允许某些用户访问该对象,而不仅仅是所有者;我是否可以只需向这种包装对象添加一个字符串数组,以跟踪被授予访问权限的用户?
以下是回答部分:
您可以再次在一个版本中实现该接口,确切地实现上述功能。
英文:
> Let's say I have a structure, like a HashMap that keeps track of what
> users I have, and let's say I identify users by their name String. How
> would I go about associating a T object inside my container to the
> String of the user who added it?
What's wrong with :
import java.util.HashMap;
import java.util.Map;
interface GenericDataContainer<T> {
public void put(String added_by, T obj);
}
class HashMapBasedContainer<T> implements GenericDataContainer<T> {
//if this lives somewhere else, make sure it's accessible from here
Map<String, T> mapper = new HashMap<>();
@Override
public void put(String added_by, T obj) {
this.mapper.put(added_by, obj);
}
}
> Let's say I also want to be able to allow certain users to access the
> object, not just the owner; could I just add an array of Strings to
> such wrapper object to keep track of users who were granted access?
You could implement the interface again in a version that does exactly that.
答案3
得分: 0
如果用户只能向您的集合中添加单个对象,那么Map<String, T>
就足够了。
那么您的put
方法实际上就是内置的Map
中的put
方法。
myMap.put(ownerString, dataOfTypeT)
如果您希望单个用户能够向您的集合中添加多个数据,则需要创建一个Map<String, List<T>>
。
那么您的put
方法在首次创建列表(如果尚不存在)后,与之前基本相同。
class MyContainer<T> {
private Map<String, List<T>> backingMap = new HashMap<>();
public void put(String userName, T data) {
if (!backingMap.containsKey(userName)) {
backingMap.put(userName, new ArrayList<>());
}
backingMap.get(userName).add(data);
}
public List<T> getAllData(String userName) {
if (!backingMap.containsKey(userName)) {
// 在我看来,返回空列表比返回 null 更合理
return List.of();
}
// 复制列表是一个好主意,这样调用者就不能修改我们的列表。
return List.copyOf(backingMap.get(userName));
}
}
如果您可以使用第三方库,Guava的ListMultimap提供类似的行为。
英文:
If a user can only ever add a single object to your collection, then a Map<String, T>
would suffice.
Then your put method is literally just the built in Map
put.
myMap.put(ownerString, dataOfTypeT)
If you want a single user to be able to add multiple data to your collection, then you want to create a Map<String,List<T>>
.
Then your put method needs to create the list first if it doesn't already exist, otherwise it's the same.
class MyContainer<T> {
private Map<String, List<T>> backingMap = new HashMap<>();
public void put(String userName, T data) {
if (!map.containsKey(userName)) {
map.put(userName, new ArrayList<>());
}
map.get(userName).add(data);
}
public List<T> getAllData(String userName) {
if (!map.get(userName)) {
// in my opinion it makes more sense to return empty list than null
return List.of()
}
// making a copy is a good idea so that the caller can't modify our list.
return List.copyOf(map.get(userName))
}
}
If you are okay with using a third party library, guava's ListMultimap provides similar behavior.
通过集体智慧和协作来改善编程学习和解决问题的方式。致力于成为全球开发者共同参与的知识库,让每个人都能够通过互相帮助和分享经验来进步。
评论