Рефакторинг до n-го уровня

Я программист-самоучка 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 яруса.

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

workmad3 23.10.2008 02:30

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

kjack 23.10.2008 13:52

да, это аналог нормализации базы данных. Джорджем, я думаю, он понял (тм)!

Steven A. Lowe 23.10.2008 19:56
ReactJs | Supabase | Добавление данных в базу данных
ReactJs | Supabase | Добавление данных в базу данных
Это и есть ваш редактор таблиц в supabase.👇
1
3
419
4
Перейти к ответу Данный вопрос помечен как решенный

Ответы 4

Для чего предназначена кнопка?

Мои первые шаги были бы такими:

  • извлеките часть доступа к базе данных. (предупреждение: впереди код воздуха)
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

Забыл воткнуть цель для кнопки. Может быть, множитель отобразить на этикетке. Спасибо за ваш ответ, ответ Стивена А. Лоу немного конкретизировал ситуацию, что для меня более понятно.

kjack 23.10.2008 12:57

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

После этого это действительно зависит от того, как спроектирована ваша программа, самый простой дизайн будет заключаться в ссылке на экземпляр 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

Спасибо, я принял ответ Стивена Лоу, потому что понял его немного лучше (хотя объективно я не могу судить, чей ответ лучше).

kjack 23.10.2008 13:18
Ответ принят как подходящий

тривиальный пример, да, но со всеми основными элементами - они просто принадлежат к 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, потому что это так легко сделать) - если вам нужно правило множителя цены в другом приложении, вы бы необходимо скопировать, вставить и отредактировать код в обработчике кнопок этого приложения. Теперь будет два места для поддержки одного и того же бизнес-правила и два места, где выполняется один и тот же запрос клиента.

Отличный ответ! Сохранение исходного кода путем его перераспределения действительно помогло с пониманием.

kjack 23.10.2008 13:28

Может ли быть, что на уровне доступа к данным будет одна функция для фактического получения данных? Чтобы во всем приложении была всего одна такая строка: set rec1 = GlobalDataBase.openrecordset (strSQL)

kjack 23.10.2008 13:29

@kjack На ваш последний вопрос нет простого ответа. Некоторые люди говорят "да", некоторые - нет. Это зависит от того, как выглядит остальная часть вашей архитектуры.

Darrel Miller 23.10.2008 17:13

Все нормально. Если одни говорят «да», а некоторые - нет, то это, по крайней мере, спорный вариант. Я думаю, это, безусловно, упростило бы переход с DAO на ADO в будущем.

kjack 23.10.2008 17:28

Умение проводить рефакторинг - это хорошо. Теперь вы будете знать, как разделять слои. Однако я думаю, что вам будет лучше потратить время на обновление инструментов, которые вы используете одновременно. Есть ли у вас возможность сделать это с помощью VB.Net?

Один из способов сохранить существующую кодовую базу - это закодировать уровень данных и BR в VB.Net. Затем выставить BR через COM-интерфейс (это опция флажка в проекте). Затем вы можете использовать новый BR из вашего текущего интерфейса.

Как только все BR и DAL будут выполнены, вы будете в шаге от совершенно новой платформы.

Неплохо подмечено. Я думаю о переносе всего на .net в будущем, но полагаю, что vb6 еще осталось несколько лет. Я думаю, что было бы проще поддерживать, улучшать и реорганизовывать существующее приложение, а также изучать ООП и т. д. В среде, в которой мне уже комфортно.

kjack 23.10.2008 13:09

Другие вопросы по теме