Я программист-самоучка vb6, использующий DAO. Ниже приведен пример типичного фрагмента кода, который я мог бы взбить:
Sub cmdMultiplier_Click() 'Button on form, user interface '
dim Rec1 as recordset
dim strSQL as string
strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID 'inline SQL '
set rec1 = GlobalDataBase.openrecordset(strSQL) ' Data access '
if rec1.bof <> true or rec1.eof <> true then
if rec1.fields("Category").value = 1 then
PriceMultiplier = 0.9 ' Business Logic '
else
priceMultiplier = 1
end if
end if
End Sub
Представьте, что это полный исходный код приложения CRUD. Я знаю, что это плохой дизайн, все перемешано. В идеале он должен иметь три отдельных уровня: пользовательский интерфейс, бизнес-логику. и доступ к данным. Я вроде как понимаю, почему это желательно, но не знаю, как это делается, и подозреваю, что поэтому я не совсем понимаю, почему такое разделение - это хорошо. Я думаю, что я был бы намного дальше, если бы кто-то мог смехотворно реорганизовать приведенное выше тривиальный пример на 3 яруса.
Я знаю, что вы имеете в виду, но я хотел посмотреть, как это делается. Поразмыслив над этим немного, я думаю, что разделение на уровни, возможно, аналогично нормализации базы данных? На поверхностном уровне кажется, что добавление сложности без какой-либо награды
да, это аналог нормализации базы данных. Джорджем, я думаю, он понял (тм)!

Для чего предназначена кнопка?
Мои первые шаги были бы такими:
function getCustomer(CurrentCustomerID as Long)
strSQL = "select * from tblCustomers where ID = " & CurrentCustomerID
set rec1 = GlobalDataBase.openrecordset(strSQL)
result = 1
if rec1.recordcount >0 then
getCustomer = rec1
else
getCustomer = false
endif
end function
function getCustomerDiscount(customerID as Long)
customer = getCustomer(customerID)
res = 1
if customer then
if customer("category")=1) then
res = .9
endif
endif
getcustomerdiscount = res
end function
Sub cmdMultiplier_Click()
pricemultiplier = getcustomerdiscount(currentcustomerid)
end sub
Забыл воткнуть цель для кнопки. Может быть, множитель отобразить на этикетке. Спасибо за ваш ответ, ответ Стивена А. Лоу немного конкретизировал ситуацию, что для меня более понятно.
Обычно у вас будет код пользовательского интерфейса, реагирующий на события, инициированные пользователем, в данном случае на нажатие кнопки.
После этого это действительно зависит от того, как спроектирована ваша программа, самый простой дизайн будет заключаться в ссылке на экземпляр Customer, и он будет содержать свойство множителя. Ваш клиентский объект заполняется из данных в вашем DAL.
Проверка пользовательского интерфейса будет проходить на уровне пользовательского интерфейса, правила бизнес-проверки могут входить в ваш бизнес-объект, и тогда ваш DAL станет вашим уровнем сохраняемости.
Вот очень простой пример псевдокода:
btnClick
Dim Cust as New Customer(ID)
multplr = Cust.DiscountMultiplier
End Click
Class Customer
Sub New(ID)
Data = DAL.GetCustomerData(ID)
Me.Name = Data("Name")
Me.Address = Data("Address")
Me.DiscountMultiplier = Data("DiscountMultiplier")
End Sub
Property ID
Property Name
Property Address
Property DiscountMultiplier
Return _discountMultiplier
End
End Class
Class DAL
Function GetCustomerData(ID)
SQL = "Paramaterized SQL"
Return Data
End Function
End Class
Спасибо, я принял ответ Стивена Лоу, потому что понял его немного лучше (хотя объективно я не могу судить, чей ответ лучше).
тривиальный пример, да, но со всеми основными элементами - они просто принадлежат к 3 разным классам (см. ниже). Основная причина этого - принцип «разделения задач», то есть графический интерфейс имеет отношение только к элементам графического интерфейса пользователя, уровень Biz Logic связан только с бизнес-правилами, а уровень доступа к данным связан только с представлениями данных. Это позволяет поддерживать каждый уровень независимо и повторно использовать в приложениях:
'in Form class - button handler
Sub cmdMultiplier_Click()
PriceMultiplier = ComputePriceMultiplier(CurrentCustomerId)
End Sub
'in Biz Logic class
Function ComputePriceMultiplier(custId as Integer) as Double
Dim cust as Customer = GetCustomer(custId)
if cust.Category = 1 then 'please ignore magic number, real code uses enums
return 0.9
end if
return 1
End Function
'in Data Access Layer class
Function GetCustomer(custId as Integer) as Customer
Dim cust as Customer = New Customer 'all fields/properties to default values
Dim strSQL as String = "select * from tblCustomers where ID = " & custId
set rec1 = GlobalDataBase.openrecordset(strSQL) ' Data access '
if rec1.bof <> true or rec1.eof <> true then
cust.SetPropertiesFromRecord(rec1)
end if
return cust
End Function
[«реальное» приложение могло бы кэшировать текущего клиента, иметь константы или хранимые процедуры для запроса клиента и т. д .; игнорируется для краткости]
Сравните это с вашим исходным примером обработчика «все в кнопке» (который ужасающе распространен в коде VB, потому что это так легко сделать) - если вам нужно правило множителя цены в другом приложении, вы бы необходимо скопировать, вставить и отредактировать код в обработчике кнопок этого приложения. Теперь будет два места для поддержки одного и того же бизнес-правила и два места, где выполняется один и тот же запрос клиента.
Отличный ответ! Сохранение исходного кода путем его перераспределения действительно помогло с пониманием.
Может ли быть, что на уровне доступа к данным будет одна функция для фактического получения данных? Чтобы во всем приложении была всего одна такая строка: set rec1 = GlobalDataBase.openrecordset (strSQL)
@kjack На ваш последний вопрос нет простого ответа. Некоторые люди говорят "да", некоторые - нет. Это зависит от того, как выглядит остальная часть вашей архитектуры.
Все нормально. Если одни говорят «да», а некоторые - нет, то это, по крайней мере, спорный вариант. Я думаю, это, безусловно, упростило бы переход с DAO на ADO в будущем.
Умение проводить рефакторинг - это хорошо. Теперь вы будете знать, как разделять слои. Однако я думаю, что вам будет лучше потратить время на обновление инструментов, которые вы используете одновременно. Есть ли у вас возможность сделать это с помощью VB.Net?
Один из способов сохранить существующую кодовую базу - это закодировать уровень данных и BR в VB.Net. Затем выставить BR через COM-интерфейс (это опция флажка в проекте). Затем вы можете использовать новый BR из вашего текущего интерфейса.
Как только все BR и DAL будут выполнены, вы будете в шаге от совершенно новой платформы.
Неплохо подмечено. Я думаю о переносе всего на .net в будущем, но полагаю, что vb6 еще осталось несколько лет. Я думаю, что было бы проще поддерживать, улучшать и реорганизовывать существующее приложение, а также изучать ООП и т. д. В среде, в которой мне уже комфортно.
Было бы очень сложно провести рефакторинг просто потому, что это до смешного тривиально. Наличие трехуровневого приложения внесло бы большую сложность в такой простой пример, что он не смог бы правильно проиллюстрировать, что трехуровневая архитектура проще, чем общая мешанина кода.