【问题标题】:Java circular referencesJava循环引用
【发布时间】:2012-05-14 09:22:31
【问题描述】:

在我正在进行的项目中,人们编写了服务类来访问 DAO。 几乎每个业务对象都有自己的服务,这些服务使用自己的 DAO。 在某些服务上,我们使用对其他服务的引用。 目前,人们正在构造函数中实例化所需的服务。

但是现在,我遇到了麻烦,因为服务 A 需要服务 B,而服务 B 需要服务 A,所以调用任一构造函数都会导致堆栈溢出...

示例(伪代码):

//Constructor of OrderService
public OrderService() {
     orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
     itemService = new ItemService();
}

//Constructor of ItemService
public ItemService() {
     itemDAO = DAOFactory.getDAOFactory().getItemDAO();
     orderService = new OrderService();
}

你会如何解决这个问题?使用单例模式?

谢谢

【问题讨论】:

    标签: java constructor stack-overflow circular-reference


    【解决方案1】:

    Spring 框架通过使用依赖注入解决了这个问题。简而言之,就是将所有的 DAO 实例化,然后在实例化之后,在主要业务逻辑之前设置 dao-dependencies。

    如果您必须手动执行此操作,这里有一个示例:

    /*
      OrderService
     */
    public OrderService ()
    {
         orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
    }
    
    public setItemService (ItemService service)
    {
         itemService = service;
    }
    
    /*
      ItemService
     */
    public ItemService ()
    {
         itemDAO = DAOFactory.getDAOFactory().getItemDAO();
    }
    
    public setOrderService (OrderService service)
    {
         orderService = service;
    }
    
    /*
       Bring it together in some other class
     */
    ...
    // instantiate singletons
    orderService = new OrderService ();
    itemService = new ItemService ();
    
    // inject dependencies
    orderService.setItemService (itemService);
    itemService.setOrderService (orderService);
    

    【讨论】:

    • 不幸的是我无法在这个项目中使用 Sprint 框架(不是我的电话,愚蠢的管理规则)
    • 然后手动进行,即:创建OrderService,ItemService。然后有 OrderService.setItemService(itemService);和 ItemService.setOrderService(orderService);
    【解决方案2】:

    让 OrderService 只处理订单。让 ItemService 只处理项目。然后创建一个将两者结合起来的 OrderItemService。

    【讨论】:

      【解决方案3】:

      是的,“单例模式”以及延迟初始化都可以。不要在构造函数中初始化服务,而是在静态 getter 中:

      class OrderService {
        private static OrderService instance;
        private OrderDAO orderDAO;
      
        public OrderService() {
          orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
        }
      
        public static synchronized OrderService getInstance() {
          if (instance == null) {
            instance = new OrderService();
          }
      
          return instance;
        }
      }
      

      作为Jonathan stated,您还可以将服务注入其他服务,但这可能不是必需的。如果同步容易导致内存问题,您可以使用volatile 解决此问题。另请参阅this answer here,详细说明“双重检查锁定模式”(但要小心,要做到这一点!)

      【讨论】:

        【解决方案4】:

        你能把“服务”从构造函数中分离出来吗?

        或者换句话说,假设您有一个 OrderService,它需要查阅它自己的 ItemService 个人副本。这个 ItemService 实例是否需要它是自己的 OrderService 副本来满足调用它的 OrderService 的请求?

        因此,这将是一种惰性初始化——除非并且直到您真正需要它,否则不要创建新项目。除非您需要,否则不要链接附加服务。

        第二个想法:你可以将副本作为构造函数的一部分传递吗?

        例如:

        //Constructor of OrderService public OrderService() 
        {     orderDAO = DAOFactory.getDAOFactory().getOrderDAO();
              itemService = new ItemService(this); 
        }
        //Constructor of ItemService public ItemService(OrderService orderService) 
        {     itemDAO = DAOFactory.getDAOFactory().getItemDAO();
              this.orderService = orderService; 
        }
        

        或者可能是相反的方向?

        【讨论】:

          猜你喜欢
          • 2010-09-15
          • 2017-05-05
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          • 1970-01-01
          相关资源
          最近更新 更多