繁体   English   中英

寻找一种设计模式和列表来存储多种类型(对象和整数)

[英]Looking for a design pattern & List to store multiple Types (object & integer)

我想我正在寻找一种设计模式,但我很难评估哪个是我需要的。

我将稍微解释一下我的设置,然后对于一些有更多经验的人来说可能会很清楚。

  • 当我的应用程序启动时,我想在不同的.java文件中创建一个类的多个对象
  • 它们的生命周期应该只在应用程序关闭时结束,所以我可以在应用程序从我的应用程序中的任何类运行时访问它们
  • 我需要以某种方式检查具有给定属性的对象是否存在
    • 假设这些对象是具有 id 和名称的用户对象,我希望能够检查是否有(如果有返回)id 为 1 的用户对象

更准确的解释:

启动时

  • 应用程序查看数据库并获取 tbl_roles 中所有角色的数据
  • 应用程序使用该数据创建角色类的对象

用户登录应用程序

  • 应用程序查看数据库以查看该用户具有哪些角色
  • 应用程序然后将角色对象映射到用户对象(用户对象有一个存储角色对象的列表)
  • 为此,应用程序必须有权访问在启动时创建的角色对象

现在我从我的数据库中读取数据,并使用该数据创建对象,但是当离开该函数时,这些对象生命周期已启动,但我希望它们一直保留到我的应用程序关闭。

我正在使用 Java & JSP & Apache Shiro Framework 开发一个 Web 应用程序

我有这个在应用程序启动时运行的类,我想我可以在这里做这个吗?

Startup.java

public class Startup implements javax.servlet.ServletContextListener {

    private static final transient Logger log = LoggerFactory.getLogger(Startup.class);

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // Code here is executed on application startup
        // create singleton object to get all roles/rights from db
        Roles_rights tmp = Roles_rights.getInstance();
        System.out.println("\nStartup.java role_list.size = " + role_list.size());

    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // Code here is executed on application close
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

Roles_rights.java

public static Roles_rights getInstance() {
    if(instance == null) {
        instance = new Roles_rights();
        instance.get_rights_of_role();
    }
    return instance;
}

public void get_rights_of_role(){
    // create object of startup class so I can access the setter method
    Startup startup = new Startup();

    // here I query my database for all roles   

    // add role to list of roles
    startup.set_RoleObject(role);
}

当我到达线路

System.out.println("\nStartup.java role_list.size = " + role_list.size());

contextInitialized方法中,它打印出列表为空(size = 0)但它只是填充了对象。

这里的问题是(在我眼里),有与无主类main将运行整个应用程序的生命周期一路功能。 每个 Java 类只是一个 servlet 或贡献给我的应用程序中使用的 servlet。

我看到的跨多个类存储数据的唯一方法是用户会话属性(但我猜应用程序本身没有会话)。

解决方案:

我解决了第一部分:

Startup.java

public class Startup implements javax.servlet.ServletContextListener {

    private static final transient Logger log = LoggerFactory.getLogger(Startup.class);
    private static Startup instance = null;

    private List<Role> role_list = new ArrayList<Role>();

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // create singleton object to get all roles/rights from db
        getInstance();
        System.out.println("\nStartup.java role_list.size = " + instance.role_list.size());
    }

    public static Startup getInstance() {
        if(instance == null) {
            instance = new Startup();
            instance.get_rights_of_role();
        }
        return instance;
    }

    // get the list of RoleObjects
    public List<Role> get_RoleObjects(){
        return role_list;
    }

}

用户.java

public class User {
    public int user_id;
    public String username;
    public List<List<?>> roles = new ArrayList<List<?>>(3);

    // get instance of Startup to access role_list
    Startup instance = Startup.getInstance();

    public void add_roles(User user, List<List<Integer>> user_roles){
        // instantiate array list
        roles.add(new ArrayList<Role>());      // stores Role Object
        roles.add(new ArrayList<Integer>());
        roles.add(new ArrayList<Integer>());

        System.out.println("\nUser.java: startup.get_RoleObjects().size = " + instance.get_RoleObjects().size());
        for(Role role : instance.get_RoleObjects()){
            if(user_roles.get(0).contains(role.role_id)){
                System.out.println("\nUser has role " + role.role_name );
            }
            System.out.println("\nUser dosnt have role" + role.role_name");
        }
    }
}

问题 2我正在寻找的第二件事是存储多种类型的对象的列表。 到目前为止,我有一个存储 3 个整数列表的列表:

public List<List<Integer>> roles = new ArrayList<List<Integer>>(3);
roles.add(new ArrayList<Integer>());
roles.add(new ArrayList<Integer>());
roles.add(new ArrayList<Integer>());

我真正想要的是一个列表,它在第一个列表中存储类的对象,在其他两个列表中存储整数,如下所示:

public List<List<Object>> roles = new ArrayList<List<Object>>(3);
roles.add(new ArrayList<Role>());    //error here (Role is a class inside my application)
roles.add(new ArrayList<Integer>()); //error here
roles.add(new ArrayList<Integer>()); //error here

第二期

我最终使用

public List<List<?>> roles = new ArrayList<List<?>>(3);
roles.add(new ArrayList<Role>());
roles.add(new ArrayList<Integer>());
roles.add(new ArrayList<Integer>());

就基本设置而言,这似乎可以解决问题。 现在在两个内部整数列表中,我想从另一个列表中添加整数值,但这现在导致错误:

List<List<Integer>> user_roles // comes from a different class to this method
user.roles.get(1).addAll(user_roles.get(1)); // error
user.roles.get(2).addAll(user_roles.get(2)); // error

错误是:

no suitable method found for allAll(List<Integer>)
  method Collection.addAll(Collection<? extends CAP#1>) is not applicable
  (argument mismatch; List<Integer> cannot be converted to Collection<? extends CAP#1>)
  method Collection.addAll(Collection<? extends CAP#1>) is not applicable
  (argument mismatch; List<Integer> cannot be converted to Collection<? extends CAP#1>)
  where CAP#1 is a fresh type-variable:
    CAP#1 extends Object from capture of ?

问题 2 的解决方案:

创建对象列表

ArrayList<ArrayList<Object>> listOfUnknownList = new ArrayList<ArrayList<Object>>();

添加了 3 个对象类型列表

listOfUnknownList.add(new ArrayList<Object>());
listOfUnknownList.add(new ArrayList<Object>());
listOfUnknownList.add(new ArrayList<Object>());

用数据填充这些列表

listOfUnknownList.get(0).add(role);                     // Adds a Role Object
listOfUnknownList.get(1).add(user_roles.get(1).get(i)); // Adds an Integer
listOfUnknownList.get(2).add(user_roles.get(2).get(i)); // Adds an Integer

好吧,您实际上并不想找到设计模式或将内容存储在列表中。 您真正想要的是使用代码解决问题。 你应该告诉我们那个问题是什么。

但是对于您的问题:应用程序初始化实际上是您的“主要”。 它是应用程序的第一部分,它将从应用程序容器接收控制。 现在值得记住的是,您的 JSP 将充当应用程序的主要驱动程序(或者可能是其他一些事件……例如数据库更新),因此实际上您的应用程序上下文应该只设置所需的信息/状态这些线程以便为用户的操作提供服务。

编辑从您下面的评论中,您担心您的范围将如何在没有主的情况下工作。 它几乎完全相同:

public class Application implements javax.servlet.ServletContextListener {

    private static final transient Logger log = LoggerFactory.getLogger(Startup.class);

    private Map<String, User> users = new HashMap<>();
    private UserRolesDb userRolesDb = new UserRolesDb("localhost:4412");

    @Override
    public void contextInitialized(ServletContextEvent sce) {
        // Code here is executed on application startup
        userRolesDb.connect();
        for(User user: validateResult(userRolesDb.getAll()) ) {
            users.put(user.getId(), user);
        }
    }

    public getUserRoles(){
        return Collections.unmodifiableMap(users);
    }

    @Override
    public void contextDestroyed(ServletContextEvent sce) {
        // Code here is executed on application close
        throw new UnsupportedOperationException("Not supported yet.");
    }
}

所以你可以在上面看到我访问数据库构建用户地图并允许访问者返回地图的非可变视图(只读)。 Application实例由应用程序容器启动,并且将在生命周期内与其引用的任何对象一样存在。 这个想法是相当粗略的,但它只是为了说明在保持对象存活方面没有什么可担心的,只需保持对Application类中的对象的引用(或在 Application 引用的另一个实例中) )。

关于你的编译问题,看起来user_roles.get(1)返回了一个List<Integer>这不是预期的......暗示user.roles.get(1)不是List<Integer>类型。

鉴于您想检查是否存在具有特定 ID 的用户的描述,尽管我会质疑您为什么不使用Map<String, User> 列表列表对我来说看起来非常不必要,但不能肯定地说,因为我不清楚你的目标是什么。

最后一点帮助:

// This list contains a list. That list has ONE TYPE. It can
// only store one kind of list.
// I cannot add a List<Role> to it.
List<List<?>> listOfListsOfUnknownTypes = new ArrayList<ArrayList<Integer>>();

// This list contains a list. That list has ONE TYPE. It can
// only store lists of OBJECTS.
// I cannot add a List<Role> to it. I cannot add a List<Integer> to it.
// I can only add List<Object> to it.
// I CAN add objects to the lists inside the list.
List<List<Object>> listOfListsOfObjects = new ArrayList<ArrayList<Object>>();

// Not sure if will compile okay actually
// This list contains unknown lists. All you know about them 
// is that they should be some kind of list. You don't know 
// what types of objects the list contains. Or even the type of 
// list. 
// BUT it is ONE type of list because you are using the CAPTURE '?'
List<? extends List<?>> listOfUnknownList = new ArrayList<ArrayList<Object>>();

// I think that what you want is this:
List<List<Object>> listOfUnknownList = new ArrayList<ArrayList<Object>>();

您正在做这种事情的事实意味着您需要重新设计您的解决方案。 这不好。 您正在尝试根据角色对列表进行索引。

同样在您的 addRoles 方法中,您应该只在this对象上使用roles成员。 我会怎么做:

public void add_roles(List<List<Integer>> user_roles){
    // instantiate array list
    for(Role role : instance.get_RoleObjects()){
        if(user_roles.get(0).contains(role.role_id)){
            // Make roles a List<Role> only
            roles.add(role); // Use the roles object on THIS
            System.out.println("\nUser has role " + role.role_name );
        }
        System.out.println("\nUser dosnt have role" + role.role_name");
    }
}

我建议您使用映射作为角色实例的集合,并将角色映射保留在应用程序范围内。 Map 将允许您根据 id 设置/获取角色实例,应用程序范围将使您的实例在整个应用程序中保持活动和可用。

编辑:创建一个与此类似的包装类

public class RoleWrapper
(
private Role role;
private int value1;
private int value2;

/*
 getter setter here
*/
}

现在在 contextInitialized() 方法中启动应用程序,创建一个映射

Map<String,RoleWrapper> roles =new HashMap<>();

现在从 DB 读取每个角色及其关联的两个整数值,创建 RoleWrapper 的实例,在其中设置所有三个值并将其放入角色映射中,其中映射键是角色 ID。

完成上述迭代后,将您的角色映射放入应用程序范围。

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM