Формализация процесса рефакторинга на основе символьной записи структуры классов

В большом количестве опубликованных работ рассматриваются использование UML-диаграмм для решения задачи синтеза и декларативные подходы к решению задачи анализа объектно ориентированных программных систем. Однако решение задачи анализа на основе UML не формализовано, а сами диаграммы дают небольшие возможности выполнять формальные преобразования над классами с целью рефакторинга проекта. Исключением в определенной части являются инструментальные средства IBM Rational. Один из возможных подходов к автоматизации процессов рефакторинга предложен в работе [28].

Автор работы на основе ряда публикаций делает вывод, что класс -это триплет вида С ={Pv,Pt, Рь}, где Pv,Pt,Pb - множество частных, защищенных и публичных данных и методов класса. С другой стороны, основываясь на свойстве инкапсуляции, класс - это пара C = {F, М},

где F - множество полей, а М- множество методов класса. Таким образом,

С = {PvF u PvM, PtF u PtM, PbF u PbM, (7.1)

где PvF, PtF, PbF - множество частных, защищенных и публичных полей класса; PvM, PtM, PbM - множество частных, защищенных и публичных методов класса.

Очевидно, что PvF е F, PtF е F, PbF е F, PvM е М, PtM е М, PbM е М, PvF п PtF = 0, PvF n PbF = 0, PtF n PbF = 0, PvM n PtM = 0, PvM n PbM = 0, PtM n PbM = 0, PvF и PtF и PbF = F, PvM и PtM и PbM = F.

Для описания структуры класса в виде символической записи предлагается следующая нотация. Символ, обозначающий атрибут класса, записывается как N*ype, где N - имя поля, a type - тип поля. Метод класса предлагается записывать как Meth'^em (рагат), где Meth - идентификатор метода, рагат - перечень формальных параметров, a prim с [virtual, abstract, override]. Допустимо, что prim = 0 и (или) рагат = 0. Класс определяется как СпатеСргть где Cprint- abstraet|0.

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

Таблица 7.1. Грамматика символьной записи структуры класса

^>=+ {[>]; [,>; [,>]}

—>

< PrvF>^

^0

< PrtF>—>

< ME THODS>^

—> ~^

< ME THODS>—>,

< PrvM >-*

^

< PrtM >^

—> abstarct0

< PubM >—>

virtual abstract override 0

—>,

^>+ |0

Таким образом, в символьном виде описание нового класса пе?С1а88, порожденного от базового класса ЬазеСаЬэ, - это выражение вида пе!СІа$.ч = ЬазеСІазз + {[/V/7, РуМ], [РР7, РіМ, \_PbF, РЬМ).

Рассмотрим пример символьной записи структуры классов, показанной в виде иМЬ-диаграммы на рис. 7.1.

иМЬ-диаграмма представления классов геометрических

Рис. 7.1. иМЬ-диаграмма представления классов геометрических

фигур

[ [fx* ? frm' ]? a-lshow^ о .Mdetima O.getrjL, ().l

TPoint =

1 setXM (newXa ), 0- )] j

%

[fia ./rrmishow^o.o,

TLine = Tpoint + ?

getXV^ai 0- setx lxirtual (newXl* ). getYlS*, 0, sef Y^-iinual (newYl“* )]

(7.

гагс/e = Tpoint +1 hide^j'Q.getR*^ 0-

(newR"* )]

Очевидно, что символьная запись структуры классов компактнее соответствующей ей иМЬ-диаграммы. Определим на основании предложенной символьной записи операции над классами для решения задачи анализа структуры проекта и его последующего рефакторинга. Определим для двух произвольных классов С1 и С2 операцию пересечения, которую будем записывать как С1 п С2. Введем в рассмотрение функцию 1{хх, х2) = [*! (х, пх2), х21 ги2)]. Пусть операция С1 п С2 в соответствии со спецификацией (1) определяется как

baseC = <

  • ?
  • ([PvFcl П PvFC2,PvMcl П PvMC2, [PtFci П PtFC2, PtMcl П PtMC2], [PbFcl П PbFC2, PЬМС1 П PbMC2

Cl П C2 — baseC +*

(7.2)

[I(PvFcl,PvFc2),I(PvMcl,PvMc2)],) [I(PtFcl,PtFc2),I(PtMcvPtMc2)], [l(PbFcv PbFCI). I(PbMcv PbMc2)]J

Базовый класс baseC - это ближайший общий предок в дереве иерархии или единый базовый класс BaseObject (NSObject, java.lang.Object, System.Object, TObject и т.п.), если такого не существует. Если реализация методов с одинаковым объявлением PvM, PtM, РЬМ различна для операндов операции пересечения, то в результате пересечения они получают дополнительный префикс abstract. Проиллюстрируем операцию строгого пересечения на примере UML-диаграммы классов, представленных на рис. 7.2.

TLine

TEllipse

TCircle

-fX 1 : int

-fX1 : int

-fX1 : int

-fYl : int

-fY1 : int

-fY1 : int

-1X2 : Int

-fR1 : int

-fR : Int

-fY2 : int

-fR2 : int

+shiow{)

?show()

+show()

+hide<)

+hlde()

+hide()

+move{)

? move()

+move()

Рис. 7.2. иМЬ-диаграмма классов без общего предка

[paint,/n

TEllipse П TLin = BaseObject + <

[showvirtual

,adstractQ’ ]

hideVirtUal,adstractO'^noreO] I TEllipse П TCircle = TEllipse П TLine,

TLine П TCircle — TEllipse П TLine. (7-3)

Результатом пересечения классов, как правило, является новый класс или общий предок классов, заявленных в качестве операндов. Таким же образом определяем операцию вычитания классов С1С2:

С1С2 =

[PvFclPvFC2,PvMclPvMcl + V мієСіМ І abstract] [PtFclPtFC2,PtMCiPtMc2 + УМІЄСІ^^abstract 1 [PbFclPbFc2.PbMclPbMcl +

^ MieCl^ ^abstract]

>

(7.4)

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

Шаг 1. Выполнить преобразование в символьную запись всех объявлений классов программной системы.

Шаг 2. Для всех классов, имеющих общего предка в дереве иерархии выполняется операция строгого пересечения:

ТРагепЮЦеМ = п'С,. (7.5)

Шаг 3. Если результат операции пересечения не равен ТРагепЮЬ-]еії Ф Ва5еОЬ]есі, определяем новый класс предка.

Шаг 4. Выполняем рефакторинг путем вычитания из каждого класса С, класса ТРагеп іОІу есі.

Рассмотрим пример рефакторинга программных классов, представленных на рисунке 7.2.

ІТ^иге = Ва$еОЪ]есТ +

ТЬіпе = ТП&ге+ {[1X2™ ,/У2ш]ШзЬ<Мокггі<кО-Ьі(іеотгіЛ0]}

ТЕІ1ір8Є = ІРі&іге+ {[/К1ШІ./К2т'].[].[57ї0М’

ТСігсІе = ТТ^кге+ {ЦІЇ™ ]Ш^ом'твггиіе (). ЬШе0^е ()]} (7.6)

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

 
< Пред   СОДЕРЖАНИЕ     След >