Является ли это циркулярной зависимостью?

является ли этот код примером циклической зависимости?

package expr;
import sheet.Sheet
public class AdressExpr implements Expr
{
    private Address address; 
    private Sheet sheet; 
    public double value(Sheet sheet)
    {
        return sheet.value(address);
    }
}
public interface Expr
{
    public double value(Sheet sheet);
}
public class Adress
{
    // omissions
}

package sheet; 
import expr.Address; 
import expr.Expr;

public class Sheet implements SuperSheet
{
    private Map <Address, Expr> map; 
    public double value(Address address)
    {
    return map.get(Address).value(this);
    }
}
public interface SuperSheet
{
    public double value(Address address);
}

Я знаю, что пример - плохое программирование, но не запрещает ли интерфейс циклическую зависимость из-за метода значений?

Ответ 1

Я думаю, что легче увидеть на диаграмме классов. Как вы можете видеть, действительно существует круговая зависимость между Sheet конкретным классом и интерфейсом Expr. Я бы не сказал, что это ОЧЕНЬ плохо, потому что я считаю, что круговая зависимость между двумя конкретными классами является наихудшей... что, конечно, не рекомендуется делать это, если это возможно.

Ваш код

enter image description here

Итак, возможно, один из способов, по которым вы можете подумать о рефакторинге, - это зависеть < SuperSheet от SuperSheet вместо Sheet и Expr от SuperSheet вместо Sheet: -

public class AdressExpr implements Expr {
    private Address address;
    private SuperSheet  sheet;

    public double value(SuperSheet sheet) {
        return sheet.value(address);
    }
}

public interface Expr {
    public double value(SuperSheet sheet);
}

...
...

... и это устранит любые нежелательные круговые зависимости.

Возможный восстановленный код

enter image description here

ПРИМЕЧАНИЕ. Я не подразумеваю, что это решение. Я просто говорю, что вы можете, конечно, посмотреть, как реорганизовать ваш код, чтобы свести к минимуму или удалить круговые зависимости, потому что круговые зависимости затрудняют ваш код unit test. Кодирование по интерфейсам всегда помогает удалить нежелательные круговые зависимости. Это также упростит ваш код unit test, потому что вы можете легко имитировать объекты.

Ответ 2

Это действительно забавный пример. Я собираюсь быть довольно подробным о моем мыслительном процессе здесь, потому что я подозреваю, что там происходит глупое именование.

Пакеты: лист выражение

Содержание листа:

  • лист
  • SuperSheet

Содержимое expr:

  • AddressExpr
  • Expr
  • Адрес

Использование в каждом:

  • AddressExpr - Expr, адрес, лист
  • Лист - SuperSheet, Адрес

Мы видим, что AddressExpr зависит от Листа, который находится в пакете листов. Одна зависимость ниже.

Мы также видим, что Лист зависит от адреса, в пакете expr.

Следовательно, у вас есть круговая зависимость между листом и пакетами expr. (Примечание: инструменты могут показать это. Я сделал это вручную, потому что ваша проблема была довольно абстрактной. Посмотрите на JDepend)

Кроме того, я даже не уверен, что когда-либо слышал о методе значений. Если компилятор может понять смысл использования двухстороннего интерфейса, он будет работать. У него есть смысл распутать беспорядок.

Ответ 3

По крайней мере, на уровне пакета. Пакет sheet зависит от пакета expr и наоборот. Основываясь на собственном опыте - я бы реорганизовал это.