Интерфейсы на различных логических слоях

Короткие и простые: поскольку элементы, которые вы ищете, не существуют в документе (пока).


В оставшуюся часть этого ответа я буду использовать getElementById как пример, но то же самое относится к getElementsByTagName , querySelector и любому другому методу DOM, который выбирает элементы.

Возможные причины

Есть две причины, по которым элемент может не существовать:

  1. Элемент с переданным идентификатором действительно не существует в документе. Вы должны дважды проверить, что идентификатор, который вы передаете на getElementById, действительно соответствует идентификатору существующего элемента в (сгенерированном) HTML и что у вас не было с ошибкой идентификатор (идентификаторы чувствительный !). Кстати, в большинстве современных браузеров , которые реализуют методы querySelector() и querySelectorAll(), нотация стиля CSS используется для извлечения элемента его id, например: document.querySelector('#elementID'), в отличие от способа, с помощью которого элемент извлекается его id в [[16]; в первом символе # необходимо, во втором это приведет к тому, что элемент не будет извлечен.
  2. Элемент не существует в данный момент , который вы вызываете getElementById ].

Последний случай довольно распространен. Браузеры анализируют и обрабатывают HTML сверху вниз. Это означает, что любой вызов элемента DOM, который встречается до появления этого элемента DOM в HTML, не будет выполнен.

Рассмотрим следующий пример:



Появляется div после script. В настоящий момент сценарий выполняется, элемент не существует , но и getElementById вернут null.

jQuery

То же самое относится к все селекторы с jQuery. jQuery не найдет элементов, если вы ошибочно написали ваш селектор, или вы пытаетесь выбрать их , прежде чем они на самом деле существуют .

Добавленный поворот - это когда jQuery не найден потому, что вы загрузили скрипт без протокола и запускаетесь из файловой системы:


этот синтаксис используется, чтобы позволить сценарию загружаться через HTTPS на странице с протоколом https: // и для загрузки HTTP-версии на странице с протоколом http: //

У этого есть неудачный побочный эффект попытки и невозможность загрузить file://somecdn.somewhere.com...


Решения

Прежде чем позвонить getElementById (или любой метод DOM, если на то пошло), убедитесь, что существуют элементы, к которым вы хотите получить доступ, т.е. загружается DOM.

Это может быть обеспечено просто добавив ваш JavaScript после к соответствующему элементу DOM

, и в этом случае вы также можете поместить код непосредственно перед тегом закрывающего тела () (все DOM элементы будут доступны в момент выполнения скрипта). [/ g3 6]

Другие решения включают прослушивание событий load [MDN] или DOMContentLoaded [MDN] . В этих случаях не имеет значения, где в документе вы помещаете код JavaScript, вам просто нужно запомнить, чтобы весь обработчик DOM обрабатывался в обработчиках событий.

Пример:

window.onload = function() {
    // process DOM elements here
};

// or

// does not work IE 8 and below
document.addEventListener('DOMContentLoaded', function() {
    // process DOM elements here
});

Более подробную информацию об обработке событий и различиях браузера см. в статьях на странице quirksmode.org .

jQuery

Сначала убедитесь, что jQuery загружен правильно , Используйте инструменты разработчика браузера , чтобы узнать, был ли найден файл jQuery и исправлен ли URL-адрес, если он не был (например, добавьте схему http: или https: в начале, отрегулируйте путь, и т. д.)

Прослушивание событий load / DOMContentLoaded - это именно то, что делает jQuery с .ready() [docs] . Весь ваш код jQuery, который влияет на элемент DOM, должен находиться внутри этого обработчика событий.

На самом деле в учебнике j8uery явно указано:

Как почти все, что мы делаем при использовании jQuery, читает или манипулирует объектной моделью документа (DOM), мы должны убедиться, что мы начинаем добавлять события и т. д., как только DOM готов.

Для этого мы регистрируем готовое событие для документа.

$(document).ready(function() {
   // do stuff when DOM is ready
});
blockquote>

В качестве альтернативы вы также можете использовать сокращенный синтаксис:

$(function() {
    // do stuff when DOM is ready
});

Оба эквивалентны.

12
задан alvonellos 8 March 2014 в 23:39
поделиться

9 ответов

Если бы я понимаю вопрос правильно, Вы создали модель предметной области, и требуется записать объектно-реляционный картопостроитель для отображения между записями в базе данных и объектах области. Однако Вы обеспокоены загрязнением Вашей модели предметной области с кодом 'инфраструктуры', который был бы необходим в чтение и записал бы в поля Вашего объекта.

Предпринимая шаги назад, у Вас по существу есть два варианта того, куда поместить Ваш код отображения данных - в самом доменном классе или во внешнем классе отображения. Первую опцию часто называют Активным Рекордным шаблоном и имеет преимущество, которое знает каждый объект, как сохранить себя и имеет достаточный доступ к его внутренней структуре, чтобы позволить ему выполнять отображение, не будучи должен выставить несвязанные с бизнесом поля.

Например,

public class User
{
    private string name;
    private AccountStatus status;

    private User()
    {
    }

    public string Name
    {
        get { return name; }
        set { name = value; }
    }

    public AccountStatus Status
    {
        get { return status; }
    }

    public void Activate()
    {
        status = AccountStatus.Active;
    }

    public void Suspend()
    {
        status = AccountStatus.Suspended;
    }

    public static User GetById(int id)
    {
        User fetchedUser = new User();

        // Lots of database and error-checking code
        // omitted for clarity
        // ...

        fetchedUser.name = (string) reader["Name"];
        fetchedUser.status = (int)reader["statusCode"] == 0 ? AccountStatus.Suspended : AccountStatus.Active;

        return fetchedUser;
    }

    public static void Save(User user)
    {
        // Code to save User's internal structure to database
        // ...
    }
}

В этом примере у нас есть объект, который представляет Пользователя с Именем и AccountStatus. Мы не хотим позволять Состоянию быть установленным непосредственно, возможно, потому что мы хотим проверить, что изменение является допустимым переходом состояния, таким образом, у нас нет метода set. К счастью, отображающийся код в GetById и Сохраняет статические методы, имеют полный доступ к имени объекта и полям состояния.

Вторая опция состоит в том, чтобы иметь второй класс, который ответственен за отображение. Это имеет преимущество разделения различных проблем бизнес-логики и персистентности, которая может позволить Вашему дизайну быть более тестируемым и гибким. Проблема с этим методом состоит в том, как выставить имя и поля состояния к внешнему классу. Некоторые опции: 1. Используйте отражение (который не имеет никаких приступов растерянности о рытье глубоко в половые органы Вашего объекта), 2. Обеспечьте особенно названный, общедоступные методы set (например, снабдите префиксом их слово 'Private'), и надеются, что никто не использует их случайно 3. Если Ваш язык поддерживает его, сделайте методы set внутренними, но предоставьте свой доступ модуля картопостроителя данных. Например, используйте InternalsVisibleToAttribute в.NET 2.0 вперед или друг функции в C++

Для получения дополнительной информации я рекомендовал бы классическую книгу Martin Fowler 'Шаблоны Архитектуры предприятия'

Однако как слово предупреждения, перед потерей работоспособности по пути записи Ваших собственных картопостроителей я настоятельно рекомендовал бы смотреть на использование стороннего инструмента объектного реляционного картопостроителя (ORM), такого как nHibernate или Платформа Объекта Microsoft. Я работал над четырьмя различными проектами, где по различным причинам мы записали наш собственный картопостроитель, и очень легко потратить впустую много времени, поддерживая и расширяя картопостроитель вместо написания кода, которое обеспечивает значение конечного пользователя. Я использовал nHibernate на одном проекте до сих пор и, хотя он имеет вполне крутую кривую обучения первоначально, инвестиции, на которых Вы вставляете рано, значительно окупаются.

6
ответ дан 2 December 2019 в 21:46
поделиться

@Ice^^Heat:

Что Вы подразумеваете под этим, уровень данных не должен знать об уровне бизнес-логики? Как Вы заполнили бы бизнес-объект данными?

UI спрашивает ServiceClass в бизнес-уровне для сервиса, а именно, получая список объектов, фильтрованных объектом с необходимыми данными параметра.
Затем ServiceClass создает экземпляр одного из классов репозитория в уровне данных и называет GetList (фильтры ParameterType).
Затем уровень данных получает доступ к базе данных, тянет данные и отображает его на распространенный формат, определенный в "доменном" блоке.
BL больше не имеет работы, чтобы сделать с этими данными, таким образом, это производит его к UI.

Затем UI хочет отредактировать Объект X. Это отправляет объект (или бизнес-объект) в службу в Бизнес-Уровне. Бизнес-уровень проверяет объект, и если он в порядке, он отправляет, он к данным разделяет на уровни для устройства хранения данных.

UI знает сервис в бизнес-уровне, который снова знает об уровне данных.

UI ответственен за отображение пользовательского ввода данных к и от объектов, и уровень данных ответственен за отображение данных в дб к и от объектов. Бизнес-уровень остается чисто бизнес-.:)

1
ответ дан 2 December 2019 в 21:46
поделиться

Это - классическая проблема - разделение Вашей модели предметной области от Вашей модели базы данных. Существует несколько способов напасть на него, это действительно зависит от размера Вашего проекта, по-моему. Вы могли использовать шаблон репозитория, как сказали другие. При использовании .NET или Java, Вы могли бы использовать NHibernate или Быть в спящем режиме.

То, что я делаю, использовать Разработку через тестирование, таким образом, я пишу свои уровни UI и Model сначала, и уровень Data дразнят, таким образом, UI и модель являются сборкой вокруг зависящих от домена объектов, затем позже я отображаюсь, они возражают против того, что когда-либо технология я использую Слой Данных. Очень плохая идея состоит в том, чтобы позволить базе данных определить дизайн Вашего приложения, записать приложение сначала и думать о данных позже.

PS заголовок вопроса немного вводит в заблуждение

5
ответ дан 2 December 2019 в 21:46
поделиться

Это могло быть решение, поскольку это не разрушит интерфейс. Я предполагаю, что у Вас мог быть класс как это:

public class BusinessObjectRecord : BusinessObject
{
}
0
ответ дан 2 December 2019 в 21:46
поделиться

Я всегда создаю отдельный блок, который содержит:

  • Много маленьких Интерфейсов (думают ICreateRepository, IReadRepository, IReadListRepsitory.. список продолжается, и большинство из них полагается в большой степени на дженерики),
  • Много конкретных Интерфейсов, как IPersonRepository, который наследовался IReadRepository, Вы понимаете..
    Что-либо, что Вы не можете описать только с меньшими интерфейсами, Вы помещаете в конкретный интерфейс.
    Пока Вы используете IPersonRepository для объявления объекта, Вы заставляете чистый, последовательный интерфейс работать с. Но строка над заголовком, можно также сделать класс, который берет f.x. ICreateRepository в его конструкторе, таким образом, код закончит тем, что был очень легок сделать некоторый действительно броский материал с. Существуют также интерфейсы для Сервисов в бизнес-уровне здесь.
  • Наконец я засовываю все объекты области в дополнительный блок, только для создания самой кодовой базы немного более чистой и более слабо связанной. Эти объекты не имеют никакой логики, они - просто распространенный способ описать данные для всех 3 + слои.

Btw. Почему Вы определили бы методы в уровне бизнес-логики для размещения уровня данных?
Уровень данных не должен иметь никакой причины даже знать, что существует бизнес-уровень..

0
ответ дан 2 December 2019 в 21:46
поделиться

Что Вы подразумеваете под этим, уровень данных не должен знать об уровне бизнес-логики? Как Вы заполнили бы бизнес-объект данными?

Я часто делаю это:

namespace Data
{
    public class BusinessObjectDataManager
    {
         public void SaveObject(BusinessObject object)
         {
                // Exec stored procedure
         {
    }
}
0
ответ дан 2 December 2019 в 21:46
поделиться

Можно хотеть разделить интерфейсы на два типа, а именно:

  • Интерфейсы представления - которые являются интерфейсами, которые указывают Ваши взаимодействия с Вашим UI, и
  • Интерфейсы передачи данных - которые являются интерфейсами, которые позволят Вам указывать взаимодействия со своими данными

Возможно наследовать и реализовать оба набора интерфейсов, таким образом что:

public class BusinessObject : IView, IData

Таким образом, в Ваших данных разделяют на уровни, только необходимо видеть интерфейсную реализацию IData, в то время как в UI только необходимо видеть интерфейсную реализацию IView.

Другая стратегия, которую Вы могли бы хотеть использовать, состоит в том, чтобы составить Ваши объекты в уровнях UI или Data, таким образом, что они просто используются этими слоями, например,

public class BusinessObject : DomainObject

public class ViewManager<T> where T : DomainObject

public class DataManager<T> where T : DomainObject

Это в свою очередь позволяет Вашему бизнес-объекту оставаться незнакомым с уровнем UI/View и о слоем данных.

0
ответ дан 2 December 2019 в 21:46
поделиться

Таким образом, проблема состоит в том, что бизнес-слой должен подвергнуть больше функциональности слою данных, и добавляющий это, функциональность означает подвергать слишком много уровню UI? Если я понимаю Вашу проблему правильно, она кажется, что Вы пытаетесь удовлетворить слишком много единственным интерфейсом, и это просто заставляет ее становиться нарушенной. Почему бы не два интерфейса на бизнес-слой? Можно было бы быть простым, безопасным интерфейсом для уровня UI. Другой был бы интерфейс низшего уровня для слоя данных.

Можно применить этот подход с двумя интерфейсами к любым объектам, которые должны быть переданы и UI и слоям данных, также.

public class BusinessLayer : ISimpleBusiness
{}

public class Some3LayerObject : ISimpleSome3LayerObject
{}
0
ответ дан 2 December 2019 в 21:46
поделиться

Я собираюсь продолжить свою привычку к хождению вразрез с мелкой частицей и сказать, что необходимо подвергнуть сомнению, почему Вы создаете все эти ужасно слои сложного объекта.

Я думаю, что многие разработчики думают о базе данных как о простом слое персистентности для их объектов и только обеспокоены в операциях CRUD, что тем объектам нужно. Слишком много усилий прикладывается к "несоответствию импеданса" между объектными и реляционными моделями. Вот идея: прекратите пробовать.

Запишите хранимые процедуры для инкапсуляции данных. Используйте наборы результатов, DataSet, DataTable, SqlCommand (или java/php/whatever эквивалент) по мере необходимости из кода для взаимодействия с базой данных. Вам не нужны те объекты. Превосходный пример встраивает SqlDataSource в.ASPX страницу.

Вы не должны пытаться скрыть свои данные от любого. Разработчики должны понять точно, как и когда они взаимодействуют с физическим хранилищем данных.

Объектно-реляционные картопостроители являются дьяволом. Прекратите использовать их.

Создание корпоративных приложений часто является упражнением в руководящей сложности. Необходимо сохранить вещи максимально простыми, или у Вас будет абсолютно неудобная в сопровождении система. Если Вы готовы позволить некоторую связь (который свойственен от любого приложения так или иначе), можно покончить и слоем бизнес-логики и с уровнем доступа к данным (заменяющий их хранимыми процедурами), и Вам не будет нужен ни один из тех интерфейсов.

0
ответ дан 2 December 2019 в 21:46
поделиться
Другие вопросы по тегам:

Похожие вопросы: