2015-10-15 8 views
2

Я хотел бы знать, как лучше всего обращаться с двунаправленной ассоциацией в O.O.P. У меня найдено несколько решений на Google и SO, но каждый из них, кажется, имеет недостаток. Язык не имеет никакого значения, но давайте использовать PHP, чтобы проиллюстрировать, что я имею в виду:Лучший способ обработки двунаправленной ассоциации в ООП

Скажем, у меня есть простые государства .. [1..n] .. Город ассоциации:

public class State { 
    public $cities; 
    public function add_city($city) {} 
} 
public class City { 
    public $state; 
    public function set_state($state) {} 
} 

РЕАЛИЗАЦИЯ # 1:

public class State { 
    public $cities; 
    public function add_city($city) { 
     $this->cities[] = $city; 
     $city->state = $this; 
    } 
} 
public class City { 
    public $state; 
    public function set_state($state) { 
     $this->state = $state; 
     $state->cities[] = $state; 
    } 
} 

две проблемы с этой реализации:

  • «$ стат e "и" $ cities "должны быть общедоступными (так что каждый может добавить город без использования публичной функции add_city ...). В большинстве языков нет концепции «friend ».
  • общественности функция может иметь, чтобы сделать какую-то операцию, прежде чем добавить

РЕАЛИЗАЦИЯ # 2:

public class State { 
    public $cities; 
    public function add_city($city) { 
     $this->cities[] = $city; 
     if ($city->state != $this) { 
      $city->set_state($this); 
     } 
    } 
} 
public class City { 
    public $state; 
    public function set_state($state) { 
     $this->state = $state; 
     if (!in_array($this, $state->cities)) { 
      $state->add_city($this); 
     } 
    } 
} 

Немного лучше, чем # 1, но функция "set_state" должен вызвать «in_array "который в сусло языке О (п)

ОСУЩЕСТВЛЕНИЯ # 3 (поворот быстрый O (1) операцию в O (N) один.):

public class State { 
    public $cities; 
    public function add_city($city, $call_the_other_function = true) { 
     $this->cities[] = $city; 
     if ($call_the_other_function) { 
      $city->set_state($this, false); 
     } 
    } 
} 
public class City { 
    public $state; 
    public function set_state($state, $call_the_other_function = true) { 
     $this->state = $state; 
     if ($call_the_other_function) { 
      $state->add_city($this, false); 
     } 
    } 
} 

Осуществление # 3 является очень эффективным, но это своего рода «уродливой» (из-за отсутствия лучшего термина) из-за дополнительного необязательного параметра

Во всяком случае, если кто имеет какие-либо идеи, что «правильный путь «(tm), я бы хотел знать.

EDIT: Если это возможно, я хотел бы решение:

  • без использования другого класса
  • Не зная порядок, в котором создан объект (т.е. не является решением проблемы «конструктор»)
+2

Вопросы «Вправо» (tm) «вне темы» для Stackoverflow, поскольку они имеют тенденцию генерировать ответы на основе мнения. Просмотрите http://stackoverflow.com/help/on-topic, чтобы узнать, о чем вы должны и не должны спрашивать. –

+0

Простите меня, но я смущен вашей первой реализацией. Почему эти переменные должны быть общедоступными? Класс «friend» мог бы использовать общедоступный метод для другого класса, не так ли? – Jacob

+0

В дополнение к тому, что сказал @TimLewis, возможно, ваш вопрос лучше подходит для [Programmers StackExchange] (http://programmers.stackexchange.com/) :) – Jacob

ответ

0

Во всех ваших предложениях Город знает о методах в государстве или наоборот. Что делать, если вы представили третий класс, ответственный за привязку городов к штатам, например LocationService одним способом, например linkCityToState? С этим вы можете впоследствии расширить его с помощью linkCityToCountry или некоторой расширенной логики, такой как getPostalCodeFromApi.

Если вы беспокоитесь о производительности, включите ваш список в hashset, что уменьшит сложность поиска до простого O(log n).

Также в вашей реализации № 1 у вас есть city->cities ...?

В любом случае, я бы никогда не решал решение № 3, если бы не программировал алгоритмы сжатия, драйверы, массивный запросов к базе данных и т. Д.

+0

Моя ошибка; я должен был добавить «без каких-либо дополнительных классов» к моему вопросу. – d08z

+0

Welp, циклические ссылки обычно решаются с введением третьего класса. –

+0

Честный вопрос: почему бы вам никогда не использовать решение №3? – d08z

2

Я бы попытался использовать конструктор, таким образом, когда вы устанавливаете город, вы можете прямо передать его состояние.

public class State { 
    private $cities; 
    public function add_city($city) { 
     $this->cities[] = $city; 
    } 
} 

public class City { 
    private $state; 
    function __construct($state) { 
     $state->add_city($this) 
     $this->state=$state 
    } 
} 
+0

Что делать, если состояние еще не создано (будет создано и связано позже), когда город создан? – d08z

+1

Необходимо указать свои варианты использования, затем код будет следовать. – NicolaSysnet

+0

Существует зависимость между городами и штатами: город относится к одному государству, штат содержит ноль или более городов. Эта зависимость требует создания города после его владения. Ответ выражает это утверждение в коде; он также обеспечивает правильную инкапсуляцию свойств. – axiac