Is it bad to pass a reference to the behavior’s owner object to the behavior?

Is it bad to pass a reference to the behavior’s owner object to the behavior? For example, if I have a Duck and DuckBehavior class. DuckBehavior is a part of the Duck Class. But what if I need to get some internal information of the Duck. Can I pass a reference of Duck to the DuckBehavior class when I’m constructing it? Or is this anti pattern circular reference?

class RubberDuck {

    DuckBehavior duckBehavior;
    string name = "Rubber Duck"; 

    public RubberDuck(){
        duckBehavior = new DuckBehavior(this);
    }
}

class DuckBehavior {
    private Duck _duck;
    public DuckBehavior(Duck duck){
        _duck = duck;
        Console.WriteLine(duck.name + " is floating.");
    }
}

0

Circular references are required for certain data structures, such as doubly-linked lists. So, circular references are not inherently evil.

Circular dependencies between libraries, projects, subsystems, or layers are usually really bad. Such dependencies often involve initialization & termination issues, which tend to thwart reliable library or subsystem bring up & tear down.

Circular references among closely related classes are usually ok.

Whether or not circular references are ok, depends somewhat on the language you’re using, such as whether it has garbage collection or not. You may have to be careful during construction & destruction.

However, some feel that these circularities should be removed by refactoring, by finding a sub-entity and promoting it to a full entity, see http://misko.hevery.com/2008/08/01/circular-dependency-in-constructors-and-dependency-injection/

Let’s also distinguish different kinds of references as to how strong of a dependence they form (the stronger the dependence, the worse a circularity would be).

When one class has an instance variable of another class, that creates a simple (data) reference. When one class (its methods) invokes another class’s instance methods that forms a simple (code) reference. Circularities among these are generally not so bad.

Still, if you can convert one or more of the classes to an interface that makes them more loosely coupled and weakens circularity issues. Or, alternately subdividing one of the classes into smaller entities can also break the circularity.

However, when one class invokes another class’es static method or constructor, this forms a stronger, direct dependence that is more than a mere reference to the theoretical type.

In your example, RubberDuck, executes new DuckBehavior(), which forms a stronger dependency than when referencing to another class thru the indirection of instances or interfaces. If DuckBehavior then, also had a reference to static field, static method, or constructor of Duck or RubberDuck, this would form a relatively strong circular dependency that might raise some eyebrows. In your example, it doesn’t, it uses an instance field/property name (presumably of Duck, which RubberDuck presumably extends; not shown).

Going further, if a static method itself makes reference to another class’es static field, method, or constructor, that makes an even stronger reference (static to static among the strongest kind of dependence). Cycles here would be frowned upon. (Of course, static are generally frowned upon in OOP anyway. There is a lot of energy in the area of dependency injection and inversion of control to eliminate the tight bindings caused by direct use of constructors.)

Stronger dependencies tend to be observable at compile time, that is to say, by static analysis of the class hierarchy and call graph. Circularities here tend to be problematic. Weaker circularities that surface only at runtime and tend to be mostly ok, especially in garbage collected languages.

Can I pass a reference of Duck to the DuckBehavior class when I’m constructing it?

Yes, I think this is ok.

Or is this anti pattern circular reference?

No, I don’t think it creates a strong circular dependency of the problematic kind; keeping in mind, of course, that looser coupling could still be had with some refactoring.

Trả lời

Email của bạn sẽ không được hiển thị công khai. Các trường bắt buộc được đánh dấu *