在设计我的类时,我目前正在努力解决循环依赖问题.
自从我读到有关贫血领域模型(我一直在做的事情)以来,我一直在努力摆脱创建只是"吸气剂和孵化器"的域对象并回到我的OO根源.
但是,下面的问题是我经常遇到的问题,我不确定应该如何解决它.
假设我们有一个Team类,有很多玩家.这是什么运动并不重要:)球队可以添加和删除球员,就像球员离开球队并加入另一支球队一样.
所以我们有一个团队,其中有一个玩家列表:
public class Team {
private List<Player> players;
// snip.
public void removePlayer(Player player) {
players.remove(player);
// Do other admin work when a player leaves
}
}
Run Code Online (Sandbox Code Playgroud)
然后我们有了Player,它引用了Team:
public class Player {
private Team team;
public void leaveTeam() {
team = null;
// Do some more player stuff...
}
}
Run Code Online (Sandbox Code Playgroud)
可以假设这两种方法(删除和离开)都具有特定于域的逻辑,只要团队移除玩家并且玩家离开团队就需要运行这些逻辑.因此,我首先想到的是当一个团队踢一个玩家时,removePlayer(...)也应该调用player.leaveTeam()方法......
但是如果玩家正在推动出发 - 如果leaveTeam()方法调用team.removePlayer(this)该怎么办?不是没有创造无限循环!
在过去,我刚刚将这些对象设为"哑"POJO,并让服务层完成工作.但即使是现在我仍然存在这个问题:为了避免循环依赖,服务层仍然将它们连接在一起 - 即
public class SomeService {
public void leave(Player player, …Run Code Online (Sandbox Code Playgroud) 我有2个泛型类,一个BaseComponentClass和一个BaseManager类.
它们既抽象又有意成为具体的.
public abstract class BaseManager<T> where T : BaseComponent<?>
public abstract class BaseComponent<T> where T : BaseManager<?>
Run Code Online (Sandbox Code Playgroud)
BaseManager有一个BaseComponents列表,这就是为什么我想让它通用,所以a PhysicsManager : BaseManager<PhysicsComponent>将有一个列表PhysicsComponents.
我想(或者更确切地说,我认为我需要)BaseComponent是通用的,因为我只希望派生的类BaseComponent被"附加"到他们适当的经理.理想情况下,我不想为每个派生组件编写构造函数,因此我可以将它添加到传递的具体管理器类中.理想情况下,我想要一个采用抽象BaseManager类的构造函数.
我怎样才能管理这种循环依赖?
在C#中,尝试编译以下代码会产生错误,"涉及'A'和'A.B'的循环基类依赖性"
public class A : A.B
{
public class B { }
}
Run Code Online (Sandbox Code Playgroud)
但是,我正在通过反编译器查看第三方DLL,并看到这种结构.这怎么可能?我只能假设第三方DLL是用其他一些.Net语言编写的,但是什么语言和语法是什么?
事实:
对我而言,这似乎是一个不错的模式,但由于经理有一个专家列表,而专家有一个经理我得到循环依赖问题.
这是一个我应该以某种方式向前宣布一个类存在于另一个类的情况吗?(如果是这样,怎么样?)或者我应该使用一些设计模式来解决这个问题?(如果是这样的话?)另外......我虽然模式本身还不错,所以我不介意有人帮助我理解为什么这是一件坏事.
我在Objective-C中重写了一个Java库,我遇到了一个奇怪的情况.我有两个相互导入的类.这是一个循环依赖.Objective-C是否支持这种情况?如果没有,你怎么建议我重写它?
我有两张桌子,News并且Files:
# unrelated columns removed
class News(db.Model):
id = db.Column(db.Integer, primary_key=True)
file_id_logo = db.Column(db.Integer, db.ForeignKey('files.id'))
logo = db.relationship('File', lazy=False)
class File(db.Model):
id = db.Column(db.Integer, primary_key=True)
news_id = db.Column(db.Integer, db.ForeignKey('news.id'))
news = db.relationship('News', lazy=False, backref=db.backref('files'))
Run Code Online (Sandbox Code Playgroud)
添加file_id_logofkey后,SQLalchemy引发了CircularDependencyError.我已经尝试post_update=True过logo关系,但它没有改变任何东西.
解决这个问题的正确方法是什么?
以下情况是可能的(如果重要):
logo.logo,引用的文件也有这个新闻news.我有一个Django应用程序,使用Celery来卸载一些任务.主要是,它推迟了数据库表中某些字段的计算.
所以,我有一个tasks.py:
from models import MyModel
from celery import shared_task
@shared_task
def my_task(id):
qs = MyModel.objects.filter(some_field=id)
for record in qs:
my_value = #do some computations
record.my_field = my_value
record.save()
Run Code Online (Sandbox Code Playgroud)
在models.py中
from django.db import models
from tasks import my_task
class MyModel(models.Model):
field1 = models.IntegerField()
#more fields
my_field = models.FloatField(null=True)
@staticmethod
def load_from_file(file):
#parse file, set fields from file
my_task.delay(id)
Run Code Online (Sandbox Code Playgroud)
显然,由于循环导入(models导入tasks和tasks导入models),这不起作用.
我暂时通过调用my_task.delay()来解决这个问题views.py,但是将模型逻辑保留在模型类中似乎是有意义的.有没有更好的方法呢?
好的我有两个模块,每个模块都包含一个类,问题是它们的类互相引用.
让我们说例如我有一个房间模块和一个包含CRoom和CPerson的人员模块.
CRoom类包含有关房间的信息,以及房间中每个人的CPerson列表.
然而,CPerson类有时需要将CRoom类用于它的房间,例如找到门,或者看看房间里还有谁.
问题是两个模块互相导入我只是得到一个导入错误,其中第二次导入:(
在c ++中,我可以通过仅包含头来解决这个问题,因为在这两种情况下类都只有指向另一个类的指针,前向声明就足以满足标题,例如:
class CPerson;//forward declare
class CRoom
{
std::set<CPerson*> People;
...
Run Code Online (Sandbox Code Playgroud)
反正有没有在python中执行此操作,除了将两个类放在同一个模块或类似的东西?
编辑:添加了使用上面的类显示问题的python示例
错误:
回溯(最近一次调用最后一次):
文件"C:\ Projects\python\test\main.py",第1行,
从房间导入CRoom
文件"C:\ Projects\python\test\room.py",第1行,
来自人员导入CPerson
文件"C:\ Projects\python\test\person.py",第1行,
从房间导入 CRoom
ImportError:无法导入名称
CRoom room.py
from person import CPerson
class CRoom:
def __init__(Self):
Self.People = {}
Self.NextId = 0
def AddPerson(Self, FirstName, SecondName, Gender):
Id = Self.NextId
Self.NextId += 1#
Person = CPerson(FirstName,SecondName,Gender,Id)
Self.People[Id] = Person
return Person
def FindDoorAndLeave(Self, PersonId):
del Self.People[PeopleId]
Run Code Online (Sandbox Code Playgroud)
person.py
from room import CRoom
class CPerson:
def __init__(Self, …Run Code Online (Sandbox Code Playgroud) 我正在使用一个包含大约30个独特模块的项目.它设计得不太好,因此在向项目添加一些新功能时创建循环导入是很常见的.
当然,当我添加循环导入时,我不知道它.有时很明显,当我得到一个像AttributeError: 'module' object has no attribute 'attribute'我明确定义的错误时,我已经进行了循环导入'attribute'.但其他时候,代码不会因为它的使用方式而抛出异常.
所以,对我的问题:
是否有可能以编程方式检测循环导入的发生时间和位置?
到目前为止,我能想到的唯一解决方案是拥有一个importTracking包含dict importingModules,一个函数的模块,该函数importInProgress(file)会递增importingModules[file],如果大于1则抛出错误,并且函数importComplete(file)会递减importingModules[file].所有其他模块看起来像:
import importTracking
importTracking.importInProgress(__file__)
#module code goes here.
importTracking.importComplete(__file__)
Run Code Online (Sandbox Code Playgroud)
但这看起来真的很讨厌,必须有更好的方法去做,对吗?
说我有这个表结构:
Client
-----------
ClientId int not null (identity)
CurrentDemographicId int null (FK to ClientDemographic)
OtherClientFields varchar(100) null
ClientDemographic
------------------
ClientDemographicId int not null (identity)
ClientId int not null (FK to Client)
OtherClientDemographicFields varchar(100) null
Run Code Online (Sandbox Code Playgroud)
我们的想法是Client(在EF中)将具有ClientDemographics列表和CurrentDemographic属性.
问题是当我设置对象结构并尝试保存它时,我收到此错误:
无法确定相关操作的有效排序.由于外键约束,模型要求或存储生成的值,可能存在依赖关系
这个错误是有道理的.我在表格设置中有一个循环引用.它不知道首先插入哪个实体(因为它同时需要来自两个表的Id).
所以,我一起破解了一个看起来像这样的解决方案:
// Save off the unchanged ClientDemograpic
ClientDemographic originalClientDemographic = client.CurrentClientDemographic;
// Merge the contract into the client object
Mapper.Map(contract, client);
// If this is a new client then add as new to the list.
if (client.ClientId == 0)
{
dataAccess.Add(client);
} …Run Code Online (Sandbox Code Playgroud)