UML Core::Abstractions: چندگانگی، Namespace، مالکیت، روابط و عناصر نوع‌دار

UML Core::Abstractions: چندگانگی، Namespace، مالکیت، روابط و عناصر نوع‌دار

توسط admin | گروه مهندسی نرم افزار | 1405/05/21

نظرات 0

9.11 package Literals

package Literals در package Abstractions، metaclassهایی برای مشخص‌کردن literal valueها تعریف می‌کند.

شکل 9.29 - package Literals
شکل 9.29 - package Literals
شکل 9.30 - عناصر تعریف‌شده در package Literals:
شکل 9.30 - عناصر تعریف‌شده در package Literals:

LiteralSpecification و specializationهای آن شامل LiteralInteger، LiteralString، LiteralBoolean، LiteralNull و LiteralUnlimitedNatural.

9.11.1 LiteralBoolean

literal Boolean مشخصه یک Boolean value است.

توصیف

literal Boolean یک attribute با value از نوع Boolean دارد.

Generalizationها

  • LiteralSpecification، صفحه 62

Attributeها

  • value: Boolean - Boolean value مشخص‌شده.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام isComputable() به‌گونه‌ای بازتعریف می‌شود که true باشد.

LiteralBoolean::isComputable(): Boolean;
isComputable = true

[2] query با نام booleanValue() همان value را برمی‌گرداند.

LiteralBoolean::booleanValue() : [Boolean];
booleanValue = value

معناشناسی

LiteralBoolean یک Boolean value ثابت را مشخص می‌کند.

نمادگذاری

LiteralBoolean متناسب با value خود با واژه true یا false نمایش داده می‌شود.

9.11.2 LiteralInteger

literal integer مشخصه یک integer value است.

توصیف

literal integer یک attribute با value از نوع Integer دارد.

Generalizationها

  • LiteralSpecification، صفحه 62

Attributeها

  • value: Integer - Integer value مشخص‌شده.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام isComputable() به‌گونه‌ای بازتعریف می‌شود که true باشد.

LiteralInteger::isComputable(): Boolean;
isComputable = true

[2] query با نام integerValue() همان value را برمی‌گرداند.

LiteralInteger::integerValue() : [Integer];
integerValue = value

معناشناسی

LiteralInteger یک Integer value ثابت را مشخص می‌کند.

نمادگذاری

LiteralInteger معمولاً به‌صورت دنباله‌ای از digitها نمایش داده می‌شود.

9.11.3 LiteralNull

literal null نبود یک value را مشخص می‌کند.

توصیف

literal null برای نمایش null، یعنی نبود value، استفاده می‌شود.

Generalizationها

  • LiteralSpecification، صفحه 62

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام isComputable() به‌گونه‌ای بازتعریف می‌شود که true باشد.

LiteralNull::isComputable(): Boolean;
isComputable = true

[2] query با نام isNull() مقدار true را برمی‌گرداند.

LiteralNull::isNull() : Boolean;
isNull = true

معناشناسی

هدف LiteralNull مدل‌کردن صریح نبود یک value است.

نمادگذاری

notation مربوط به LiteralNull بسته به محل استفاده متفاوت است. اغلب به‌صورت واژه null ظاهر می‌شود. notationهای دیگر برای کاربردهای مشخص در بخش‌های مربوطه شرح داده می‌شوند.

9.11.4 LiteralSpecification

literal specification یک literal constant مدل‌شده را شناسایی می‌کند.

توصیف

literal specification یک specialization انتزاعی از ValueSpecification است که یک literal constant مدل‌شده را شناسایی می‌کند.

Generalizationها

  • ValueSpecification، صفحه 48

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

معناشناسی

معناشناسی اضافی وجود ندارد. subclassهای LiteralSpecification برای مشخص‌کردن literal valueهای typeهای مختلف تعریف می‌شوند.

نمادگذاری

نمادگذاری مشخصی وجود ندارد.

9.11.5 LiteralString

literal string مشخصه یک string value است.

توصیف

literal string یک attribute با value از نوع String دارد.

Generalizationها

  • LiteralSpecification، صفحه 62

Attributeها

  • value: String - String value مشخص‌شده.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام isComputable() به‌گونه‌ای بازتعریف می‌شود که true باشد.

LiteralString::isComputable(): Boolean;
isComputable = true

[2] query با نام stringValue() همان value را برمی‌گرداند.

LiteralString::stringValue() : [String];
stringValue = value

معناشناسی

LiteralString یک String value ثابت را مشخص می‌کند.

نمادگذاری

LiteralString به‌صورت دنباله‌ای از characterها داخل double quote نمایش داده می‌شود. character set مورد استفاده مشخص نشده است.

9.11.6 LiteralUnlimitedNatural

literal unlimited natural مشخصه یک unlimited natural number است.

توصیف

literal unlimited natural یک attribute با value از نوع UnlimitedNatural دارد.

Generalizationها

  • LiteralSpecification، صفحه 62

Attributeها

  • value: UnlimitedNatural - UnlimitedNatural value مشخص‌شده.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام isComputable() به‌گونه‌ای بازتعریف می‌شود که true باشد.

LiteralUnlimitedNatural::isComputable(): Boolean;
isComputable = true

[2] query با نام unlimitedValue() همان value را برمی‌گرداند.

LiteralUnlimitedNatural::unlimitedValue() : [UnlimitedNatural];
unlimitedValue = value

معناشناسی

LiteralUnlimitedNatural یک UnlimitedNatural value ثابت را مشخص می‌کند.

نمادگذاری

LiteralUnlimitedNatural یا به‌صورت دنباله‌ای از digitها یا با علامت asterisk (*) نمایش داده می‌شود؛ asterisk در اینجا به معنای unlimited است، نه infinity.

9.12 package Multiplicities

subpackage Multiplicities از package Abstractions کلاس‌های metamodel مورد استفاده برای پشتیبانی از مشخصه‌سازی multiplicity برای typed elementها، مانند association endها و attributeها، و نیز تعیین ordered یا unique بودن elementهای چندمقداری را تعریف می‌کند.

شکل 9.31 - package Multiplicities
شکل 9.31 - package Multiplicities
شکل 9.32 - عناصر تعریف‌شده در package Multiplicities
شکل 9.32 - عناصر تعریف‌شده در package Multiplicities

9.12.1 MultiplicityElement

multiplicity تعریف یک interval شامل دو کران از integerهای نامنفی است که از lower bound آغاز می‌شود و به upper bound، که ممکن است نامتناهی باشد، پایان می‌یابد. multiplicity element این اطلاعات را در خود جای می‌دهد تا cardinalityهای مجاز برای یک instantiation از همان element را مشخص کند.

توصیف

MultiplicityElement یک metaclass انتزاعی است که attributeهای اختیاری برای تعریف boundهای multiplicity دارد. همچنین مشخص می‌کند valueهای موجود در یک instantiation از این element باید unique یا ordered باشند یا خیر.

Generalizationها

  • Element، صفحه 44

Attributeها

  • isOrdered: Boolean - برای multiplicity چندمقداری تعیین می‌کند آیا valueهای یک instantiation از element به‌ترتیب دنباله‌ای مرتب هستند یا خیر. مقدار پیش‌فرض false است.
  • isUnique: Boolean - برای multiplicity چندمقداری تعیین می‌کند آیا valueهای یک instantiation از element unique هستند یا خیر. مقدار پیش‌فرض true است.
  • lower: Integer[0..1] - lower bound بازه multiplicity را مشخص می‌کند. مقدار پیش‌فرض 1 است.
  • upper: UnlimitedNatural[0..1] - upper bound بازه multiplicity را مشخص می‌کند. مقدار پیش‌فرض 1 است.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

این constraintها باید موقعیت‌هایی را نیز پوشش دهند که upper bound ممکن است با expressionای مشخص شده باشد که در model قابل محاسبه نیست. در این package چنین وضعیتی رخ نمی‌دهد، اما در subclassها ممکن است رخ دهد.

[1] یک multiplicity باید حداقل یک cardinality معتبر بزرگ‌تر از صفر تعریف کند.

upperBound()->notEmpty() implies upperBound() > 0

[2] lower bound باید یک integer literal نامنفی باشد.

lowerBound()->notEmpty() implies lowerBound() >= 0

[3] upper bound باید بزرگ‌تر یا مساوی lower bound باشد.

(upperBound()->notEmpty() and lowerBound()->notEmpty()) implies upperBound() >= lowerBound()

Operationهای اضافی

[1] query با نام isMultivalued() بررسی می‌کند آیا upper bound این multiplicity از 1 بزرگ‌تر است یا خیر.

MultiplicityElement::isMultivalued() : Boolean;
pre: upperBound()->notEmpty()
isMultivalued = (upperBound() > 1)

[2] query با نام includesCardinality() بررسی می‌کند آیا cardinality مشخص‌شده برای این multiplicity معتبر است یا خیر.

MultiplicityElement::includesCardinality(C : Integer) : Boolean;
pre: upperBound()->notEmpty() and lowerBound()->notEmpty()
includesCardinality = (lowerBound() <= C) and (upperBound() >= C)

[3] query با نام includesMultiplicity() بررسی می‌کند آیا این multiplicity همه cardinalityهای مجاز توسط multiplicity مشخص‌شده را در بر می‌گیرد یا خیر.

MultiplicityElement::includesMultiplicity(M : MultiplicityElement) : Boolean;
pre: self.upperBound()->notEmpty() and self.lowerBound()->notEmpty()
     and M.upperBound()->notEmpty() and M.lowerBound()->notEmpty()
includesMultiplicity = (self.lowerBound() <= M.lowerBound()) and (self.upperBound() >= M.upperBound())

[4] query با نام lowerBound() lower bound multiplicity را به‌صورت integer برمی‌گرداند.

MultiplicityElement::lowerBound() : [Integer];
lowerBound = if lower->notEmpty() then lower else 1 endif

[5] query با نام upperBound() upper bound multiplicity bounded را به‌صورت unlimited natural برمی‌گرداند.

MultiplicityElement::upperBound() : [UnlimitedNatural];
upperBound = if upper->notEmpty() then upper else 1 endif

معناشناسی

multiplicity مجموعه‌ای از integerها را تعریف می‌کند که cardinalityهای معتبر را مشخص می‌کنند. به‌طور مشخص، cardinality با نام C برای multiplicity با نام M زمانی معتبر است که M.includesCardinality(C) برقرار باشد.

multiplicity به‌صورت intervalای از integerها مشخص می‌شود که از lower bound آغاز و به upper bound، که ممکن است نامتناهی باشد، ختم می‌شود.

اگر MultiplicityElement یک multiplicity چندمقداری مشخص کند، instantiation آن element مجموعه‌ای از valueها خواهد داشت. multiplicity قیدی بر تعداد valueهایی است که می‌توانند به‌طور معتبر در آن مجموعه ظاهر شوند.

اگر MultiplicityElement به‌صورت ordered مشخص شده باشد، یعنی isOrdered=true، مجموعه valueها در instantiation آن element ordered است. این ordering به معنای وجود نگاشتی از integerهای مثبت به elementهای مجموعه valueهاست. اگر MultiplicityElement چندمقداری نباشد، value مربوط به isOrdered اثر معنایی ندارد.

اگر MultiplicityElement به‌صورت unordered مشخص شده باشد، یعنی isOrdered=false، درباره ترتیب valueهای instantiation آن element هیچ فرضی نمی‌توان داشت.

اگر MultiplicityElement به‌صورت unique مشخص شده باشد، یعنی isUnique=true، مجموعه valueها در instantiation آن element باید unique باشد. اگر MultiplicityElement چندمقداری نباشد، value مربوط به isUnique اثر معنایی ندارد.

نمادگذاری

notation مشخص MultiplicityElement توسط subclassهای عینی تعریف می‌شود. به‌طور کلی notation شامل multiplicity specification است که به‌صورت رشته متنی شامل boundهای interval نمایش داده می‌شود، همراه با notationی برای نمایش مشخصه‌های اختیاری ordering و uniqueness.

boundهای multiplicity معمولاً با قالب زیر نمایش داده می‌شوند:

<lower-bound> '..' <upper-bound>

که در آن <lower-bound> یک integer نامنفی و <upper-bound> یک unlimited natural number است. asterisk (*) در multiplicity specification برای نمایش upper bound نامحدود یا بی‌نهایت استفاده می‌شود.

اگر Multiplicity با elementی وابسته باشد که notation آن یک رشته متنی است، مانند attribute، رشته multiplicity به‌عنوان بخشی از همان رشته در square bracket [] قرار می‌گیرد. شکل 9.33 دو رشته multiplicity را به‌عنوان بخشی از مشخصات attribute در نماد class نشان می‌دهد.

اگر Multiplicity با elementی وابسته باشد که به‌صورت symbol نمایش داده می‌شود، مانند association end، رشته multiplicity بدون square bracket نمایش داده می‌شود و می‌تواند نزدیک نماد element قرار گیرد. شکل 9.34 دو رشته multiplicity را به‌عنوان بخشی از مشخصه دو association end نشان می‌دهد.

notation مشخص ordering و uniqueness ممکن است بر اساس subclass خاص MultiplicityElement متفاوت باشد. notation عمومی استفاده از property string شامل ordered یا unordered برای ordering و unique یا nonunique برای uniqueness است.

گزینه‌های ارائه

اگر lower bound و upper bound برابر باشند، notation جایگزین می‌تواند فقط رشته upper bound را نمایش دهد. برای مثال 1 از نظر معنایی معادل 1..1 است.

multiplicity با lower bound برابر صفر و upper bound نامشخص می‌تواند از notation جایگزین تک asterisk یعنی * به‌جای 0..* استفاده کند.

BNF زیر syntax رشته multiplicity را همراه با گزینه‌های ارائه فوق تعریف می‌کند:

<multiplicity> ::= <multiplicity-range>
                [ [ '{' <order-designator> [',' <uniqueness-designator> ] '}' ] |
                 [ '{' <uniqueness-designator> [',' <order-designator> ] '}' ] ]
<multiplicity-range> ::= [ <lower> '..' ] <upper>
<lower> ::= <integer> | <value-specification>
<upper> ::= '*' | <value-specification>
<order-designator> ::= 'ordered' | 'unordered'
<uniqueness-designator> ::= 'unique' | 'nonunique'

مثال‌ها

شکل 9.33 - multiplicity درون مشخصه متنی
شکل 9.33 - multiplicity درون مشخصه متنی
Customer
purchase : Purchase [*] {ordered, unique}
account: Account [0..5] {unique}
شکل 9.34 - multiplicity به‌عنوان adornment یک symbol:
شکل 9.34 - multiplicity به‌عنوان adornment یک symbol:

association purchase میان Purchase و Customer با * {ordered, unique} و association account میان Customer و Account با 0..5 {unique} نمایش داده شده است.

منطق طراحی

MultiplicityElement یک trade-off طراحی را برای بهبود برخی نگاشت‌های فناوری مانند XMI نمایش می‌دهد.

9.13 package MultiplicityExpressions

subpackage MultiplicityExpressions از package Abstractions قابلیت‌های multiplicity را برای پشتیبانی از value expressionها به‌عنوان bound گسترش می‌دهد.

شکل 9.35 - package MultiplicityExpressions
شکل 9.35 - package MultiplicityExpressions
شکل 9.36 - عناصر تعریف‌شده در package MultiplicityExpressions
شکل 9.36 - عناصر تعریف‌شده در package MultiplicityExpressions

9.13.1 MultiplicityElement (تخصصی‌شده)

توصیف

MultiplicityElement تخصصی می‌شود تا استفاده از value specification برای تعریف هر bound از multiplicity را پشتیبانی کند.

Generalizationها

  • MultiplicityElement، صفحه 65
  • Element (as specialized)، صفحه 74

Attributeها

  • /lower: Integer[0..1] - lower bound بازه multiplicity را، اگر به‌صورت integer بیان شود، مشخص می‌کند. این بازتعریف property متناظر از Multiplicities است.
  • /upper: UnlimitedNatural[0..1] - upper bound بازه multiplicity را، اگر به‌صورت unlimited natural بیان شود، مشخص می‌کند. این بازتعریف property متناظر از Multiplicities است.

Associationها

  • lowerValue: ValueSpecification[0..1] - specification مربوط به lower bound این multiplicity. زیرمجموعه Element::ownedElement است.
  • upperValue: ValueSpecification[0..1] - specification مربوط به upper bound این multiplicity. زیرمجموعه Element::ownedElement است.

Constraintها

[1] اگر برای lower یا upper bound از ValueSpecification استفاده شود، ارزیابی آن specification نباید side effect داشته باشد. در OCL قابل بیان نیست.

[2] اگر برای lower یا upper bound از ValueSpecification استفاده شود، آن specification باید یک constant expression باشد. در OCL قابل بیان نیست.

[3] attribute مشتق‌شده lower باید برابر lowerBound() باشد.

lower = lowerBound()

[4] attribute مشتق‌شده upper باید برابر upperBound() باشد.

upper = upperBound()

Operationهای اضافی

[1] query با نام lowerBound() lower bound multiplicity را به‌صورت integer برمی‌گرداند.

MultiplicityElement::lowerBound() : [Integer];
lowerBound =
     if lowerValue->isEmpty() then
           1
     else
           lowerValue.integerValue()
     endif

[2] query با نام upperBound() upper bound multiplicity را به‌صورت unlimited natural برمی‌گرداند.

MultiplicityElement::upperBound() : [UnlimitedNatural];
upperBound =
     if upperValue->isEmpty() then
           1
     else
           upperValue.unlimitedValue()
     endif

معناشناسی

lower و upper bound مربوط به multiplicity یک MultiplicityElement می‌توانند با value specificationهایی مانند expressionهای ثابت و بدون side effect مشخص شوند.

نمادگذاری

notation مربوط به Multiplicities::MultiplicityElement برای پشتیبانی از value specificationها در boundها گسترش یافته است.

BNF زیر syntax یک multiplicity string را، همراه با پشتیبانی از گزینه‌های ارائه، تعریف می‌کند:

<multiplicity> ::= <multiplicity-range>
                [ [ '{' <order-designator> [',' <uniqueness-designator> ] '}' ] |
                 [ '{' <uniqueness-designator> [',' <order-designator> ] '}' ] ]
<multiplicity-range> ::= [ <lower> '..' ] <upper>
<lower> ::= <integer> | <value-specification>
<upper> ::= '*' | <value-specification>
<order-designator> ::= 'ordered' | 'unordered'
<uniqueness-designator> ::= 'unique' | 'nonunique'

9.14 package Namespaces

subpackage Namespaces از package Abstractions مفاهیم مورد استفاده برای تعریف model elementهای دارای نام، و نیز containment و identification این named elementها درون namespaceها را مشخص می‌کند.

شکل 9.37 - package Namespaces
شکل 9.37 - package Namespaces
شکل 9.38 - عناصر تعریف‌شده در package Namespaces
شکل 9.38 - عناصر تعریف‌شده در package Namespaces

9.14.1 NamedElement

named element عنصری در model است که ممکن است نام داشته باشد.

توصیف

named element، elementهایی را نمایش می‌دهد که می‌توانند name داشته باشند. name برای شناسایی named element در namespaceای که element در آن تعریف شده است استفاده می‌شود. named element همچنین یک qualified name دارد که امکان شناسایی بدون ابهام آن را در hierarchy از namespaceهای تو در تو فراهم می‌کند. NamedElement یک metaclass انتزاعی است.

Generalizationها

  • Element (as specialized)، صفحه 74

Attributeها

  • name: String[0..1] - نام NamedElement.
  • /qualifiedName: String[0..1] - نامی که امکان شناسایی NamedElement را در hierarchy از Namespaceهای تو در تو فراهم می‌کند. این نام از nameهای namespaceهای دربرگیرنده، از root hierarchy تا name خود NamedElement، ساخته می‌شود. attribute مشتق‌شده است.

Associationها

  • /namespace: Namespace[0..1] - namespace مالک NamedElement را مشخص می‌کند. زیرمجموعه Element::owner است و یک derived union محسوب می‌شود.

Constraintها

[1] اگر name وجود نداشته باشد یا یکی از namespaceهای دربرگیرنده بدون name باشد، qualified name نیز وجود ندارد.

(self.name->isEmpty() or self.allNamespaces()->select(ns | ns.name->isEmpty())->notEmpty())
     implies self.qualifiedName->isEmpty()

[2] هنگامی که name وجود دارد و تمام namespaceهای دربرگیرنده نیز name دارند، qualified name از nameهای namespaceهای دربرگیرنده ساخته می‌شود.

(self.name->notEmpty() and self.allNamespaces()->select(ns | ns.name->isEmpty())->isEmpty()) implies
     self.qualifiedName = self.allNamespaces()->iterate( ns : Namespace; result: String = self.name |
          ns.name->union(self.separator())->union(result))

Operationهای اضافی

[1] query با نام allNamespaces() دنباله namespaceهایی را که NamedElement در آن‌ها nested شده است، از داخل به بیرون، برمی‌گرداند.

NamedElement::allNamespaces(): Sequence(Namespace);
allNamespaces =
   if self.namespace->isEmpty()
   then Sequence{}
   else self.namespace.allNamespaces()->prepend(self.namespace)
   endif

[2] query با نام isDistinguishableFrom() تعیین می‌کند آیا دو NamedElement می‌توانند از نظر منطقی در یک Namespace هم‌زمان وجود داشته باشند یا خیر. به‌طور پیش‌فرض، دو named element زمانی distinguishable هستند که یا typeهای نامرتبط داشته باشند، یا typeهای مرتبط ولی nameهای متفاوت.

NamedElement::isDistinguishableFrom(n:NamedElement, ns: Namespace): Boolean;
isDistinguishable =
  if self.oclIsKindOf(n.oclType) or n.oclIsKindOf(self.oclType)
  then ns.getNamesOfMember(self)->intersection(ns.getNamesOfMember(n))->isEmpty()
  else true
  endif

[3] query با نام separator() رشته‌ای را برمی‌گرداند که هنگام ساخت qualified name برای جداسازی nameها استفاده می‌شود.

NamedElement::separator(): String;
separator = '::'

معناشناسی

attribute با نام name برای شناسایی named element در namespaceهایی استفاده می‌شود که name آن element در آن‌ها accessible است. توجه کنید multiplicity این attribute برابر [0..1] است؛ بنابراین امکان نبود name را فراهم می‌کند، که با name تهی تفاوت دارد.

9.14.2 Namespace

namespace عنصری در model است که مجموعه‌ای از named elementها را در خود نگه می‌دارد و می‌توان آن‌ها را با name شناسایی کرد.

توصیف

namespace یک named element است که می‌تواند مالک named elementهای دیگر باشد. هر named element حداکثر می‌تواند در مالکیت یک namespace باشد. namespace راهی برای شناسایی named elementها با name فراهم می‌کند. named elementها می‌توانند در namespace یا مستقیماً در مالکیت namespace باشند یا از راه‌های دیگری، مانند importing یا inheritance، به namespace معرفی شوند. Namespace یک metaclass انتزاعی است.

Generalizationها

  • Namespace، صفحه 72

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • /member: NamedElement[*] - مجموعه NamedElementهایی که در Namespace قابل شناسایی‌اند، چه در مالکیت مستقیم آن باشند و چه از طریق importing یا inheritance معرفی شده باشند. derived union است.
  • /ownedMember: NamedElement[*] - مجموعه NamedElementهایی که در مالکیت Namespace هستند. زیرمجموعه Element::ownedElement و Namespace::member است و derived union محسوب می‌شود.

Constraintها

[1] تمام memberهای یک Namespace باید درون آن از یکدیگر distinguishable باشند.

membersAreDistinguishable()

Operationهای اضافی

[1] query با نام getNamesOfMember() مجموعه همه nameهایی را که یک member در یک Namespace می‌تواند داشته باشد برمی‌گرداند. به‌طور کلی member می‌تواند در یک Namespace چند name داشته باشد اگر بیش از یک بار و با aliasهای متفاوت import شده باشد. این معناشناسی با override کردن operation با نام getNamesOfMember مشخص می‌شود. مشخصات حاضر صرفاً مجموعه‌ای شامل یک name یا در صورت نبود name، مجموعه تهی، برمی‌گرداند.

Namespace::getNamesOfMember(element: NamedElement): Set(String);
getNamesOfMember =
    if member->includes(element) then Set{}->including(element.name) else Set{} endif

[2] query بولی membersAreDistinguishable() تعیین می‌کند آیا تمام memberهای namespace درون آن distinguishable هستند یا خیر.

Namespace::membersAreDistinguishable() : Boolean;
membersAreDistinguishable =
self.member->forAll( memb |
     self.member->excluding(memb)->forAll(other |
          memb.isDistinguishableFrom(other, self)))

معناشناسی

namespace یک container برای named elementها فراهم می‌کند و راهی برای resolve کردن nameهای composite مانند name1::name2::name3 ارائه می‌دهد. association با نام member تمام named elementهای namespace با نام N را مشخص می‌کند که می‌توان با composite name به‌شکل N::<x> به آن‌ها ارجاع داد. توجه کنید این مجموعه با همه nameهایی که بدون qualification در N قابل ارجاع‌اند متفاوت است، زیرا مجموعه دوم memberهای پنهان‌نشده namespaceهای enclosing را نیز شامل می‌شود.

named elementها می‌توانند طبق قواعدی که تعیین می‌کنند چگونه یک named element از دیگری distinguishable است درون namespace ظاهر شوند. قاعده پیش‌فرض این است که دو element زمانی distinguishable هستند که typeهای نامرتبط داشته باشند یا typeهای مرتبط با nameهای متفاوت داشته باشند. این قاعده می‌تواند برای موارد خاص override شود؛ برای مثال operationهایی که با signature خود متمایز می‌شوند.

نمادگذاری

نمادگذاری اضافی وجود ندارد. subclassهای عینی notation خاص خود را تعریف می‌کنند.

9.15 package Ownerships

subpackage Ownerships از package Abstractions، Element بنیادی را برای پشتیبانی از مالکیت elementهای دیگر گسترش می‌دهد.

شکل 9.39 - package Ownerships
شکل 9.39 - package Ownerships
شکل 9.40 - عناصر تعریف‌شده در package Ownerships
شکل 9.40 - عناصر تعریف‌شده در package Ownerships

9.15.1 Element (به‌صورت تخصصی‌شده)

element یکی از اجزای model است و در این نقش قابلیت مالکیت elementهای دیگر را دارد.

توصیف

Element یک composition association مشتق‌شده با خودش دارد تا قابلیت عمومی مالکیت elementهای دیگر توسط elementها پشتیبانی شود.

Generalizationها

  • Element، صفحه 44

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • /ownedElement: Element[*] - Elementهایی که در مالکیت این element هستند. derived union است.
  • /owner: Element[0..1] - Element مالک این element. derived union است.

Constraintها

[1] یک element نمی‌تواند به‌طور مستقیم یا غیرمستقیم مالک خودش باشد.

not self.allOwnedElements()->includes(self)

[2] elementهایی که باید تحت مالکیت باشند، باید owner داشته باشند.

self.mustBeOwned() implies owner->notEmpty()

Operationهای اضافی

[1] query با نام allOwnedElements() همه elementهای مستقیم و غیرمستقیم در مالکیت یک element را برمی‌گرداند.

Element::allOwnedElements(): Set(Element);
allOwnedElements = ownedElement->union(ownedElement->collect(e | e.allOwnedElements()))

[2] query با نام mustBeOwned() مشخص می‌کند elementهای این type باید owner داشته باشند یا خیر. subclassهای Element که owner برای آن‌ها الزامی نیست باید این operation را override کنند.

Element::mustBeOwned() : Boolean;
mustBeOwned = true

معناشناسی

subclassهای Element معناشناسی مناسب مفهوم خود را فراهم می‌کنند.

association مشتق‌شده ownedElement به‌صورت مستقیم یا غیرمستقیم توسط همه composed association endهای metamodel subset می‌شود. بنابراین ownedElement راهی مناسب برای دسترسی به همه elementهایی فراهم می‌کند که مستقیماً در مالکیت یک Element هستند.

نمادگذاری

برای Element notation عمومی وجود ندارد. subclassهای مشخص Element notation خود را تعریف می‌کنند.

9.16 package Redefinitions

package Redefinitions در package Abstractions قابلیت عمومی بازتعریف model elementها را در context یک hierarchy generalization مشخص می‌کند.

شکل 9.41 - package Redefinitions
شکل 9.41 - package Redefinitions
شکل 9.42 - عناصر تعریف‌شده در package Redefinitions
شکل 9.42 - عناصر تعریف‌شده در package Redefinitions

9.16.1 RedefinableElement

redefinable element عنصری است که وقتی در context یک classifier تعریف شده باشد، می‌تواند در context classifier دیگری که به‌طور مستقیم یا غیرمستقیم classifier اول را تخصصی می‌کند، با جزئیات بیشتر یا به‌شکلی متفاوت بازتعریف شود.

توصیف

redefinable element یک named element است که می‌تواند در context یک generalization بازتعریف شود. RedefinableElement یک metaclass انتزاعی است.

Generalizationها

  • NamedElement، صفحه 71

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • /redefinedElement: RedefinableElement[*] - redefinable elementای که توسط این element بازتعریف می‌شود. derived union است.
  • /redefinitionContext: Classifier[*] - contextهایی را مشخص می‌کند که این element ممکن است از آن‌ها بازتعریف شود. derived union است.

Constraintها

[1] حداقل یکی از redefinition contextهای element بازتعریف‌کننده باید specialization حداقل یکی از redefinition contextهای هر element بازتعریف‌شده باشد.

self.redefinedElement->forAll(e | self.isRedefinitionContextValid(e))

[2] element بازتعریف‌کننده باید با هر element بازتعریف‌شده سازگار باشد.

self.redefinedElement->forAll(re | re.isConsistentWith(self))

Operationهای اضافی

[1] query با نام isConsistentWith() برای هر دو RedefinableElement در contextی که redefinition ممکن است تعیین می‌کند آیا redefinition از نظر منطقی سازگار خواهد بود یا خیر. مقدار پیش‌فرض false است؛ این operation باید در subclassهای RedefinableElement override شود تا شرایط سازگاری تعریف شود.

RedefinableElement::isConsistentWith(redefinee: RedefinableElement): Boolean;
pre: redefinee.isRedefinitionContextValid(self)
isConsistentWith = false

[2] query با نام isRedefinitionContextValid() تعیین می‌کند redefinition contextهای این RedefinableElement به‌درستی با redefinition contextهای RedefinableElement مشخص‌شده مرتبط هستند یا خیر تا این element بتواند دیگری را بازتعریف کند. به‌طور پیش‌فرض، حداقل یکی از redefinition contextهای این element باید specialization حداقل یکی از redefinition contextهای element مشخص‌شده باشد.

RedefinableElement::isRedefinitionContexValid(redefinable: RedefinableElement): Boolean;
RedefinableElement::isRedefinitionContextValid
   (redefined:RedefinableElement):Boolean;
   isRedifinitionContextValid =
        redefinitionContext->exists(c |
             c.allparents()->
                  includes (redefined.redefinitionContext))
                            )

معناشناسی

RedefinableElement قابلیت عمومی بازتعریف‌شدن در context یک generalization relationship را نمایش می‌دهد. معناشناسی دقیق redefinition برای هر specialization از RedefinableElement متفاوت است.

redefinable element یک specification درباره instanceهای classifierای است که یکی از redefinition contextهای element محسوب می‌شود. برای classifierای که آن classifier عمومی‌تر را به‌طور مستقیم یا غیرمستقیم تخصصی می‌کند، element دیگری می‌تواند element متعلق به classifier عمومی را بازتعریف کند تا specification را برای instanceهای classifier تخصصی‌کننده گسترش دهد، محدود کند یا override نماید.

element بازتعریف‌کننده باید با elementی که بازتعریف می‌کند سازگار باشد، اما می‌تواند constraintهای مشخص یا جزئیات دیگری اضافه کند که ویژه instanceهای redefinition context تخصصی‌کننده هستند و با invariant constraintهای context عمومی تناقض ندارند.

یک redefinable element می‌تواند چند بار بازتعریف شود. همچنین یک element بازتعریف‌کننده واحد می‌تواند چند redefinable element موروثی را بازتعریف کند.

نقاط تغییرپذیری معنایی

میان element بازتعریف‌شده و element بازتعریف‌کننده درجات مختلفی از compatibility وجود دارد؛ مانند name compatibility، که در آن element بازتعریف‌کننده همان name element بازتعریف‌شده را دارد؛ structural compatibility، که در آن propertyهای قابل مشاهده برای client در element بازتعریف‌شده در element بازتعریف‌کننده نیز وجود دارند؛ یا behavioral compatibility، که در آن element بازتعریف‌کننده می‌تواند جایگزین element بازتعریف‌شده شود. هر نوع compatibility شامل constraintی روی redefinitionهاست. constraint مشخصی که انتخاب می‌شود یک semantic variation point محسوب می‌شود.

نمادگذاری

notation عمومی وجود ندارد. برای notation مشخص به subclassهای RedefinableElement مراجعه کنید.

9.17 package Relationships

subpackage Relationships از package Abstractions پشتیبانی از directed relationshipها را اضافه می‌کند.

شکل 9.43 - package Relationships
شکل 9.43 - package Relationships
شکل 9.44 - عناصر تعریف‌شده در package Relationships
شکل 9.44 - عناصر تعریف‌شده در package Relationships

9.17.1 DirectedRelationship

directed relationship رابطه‌ای میان collectionی از source model elementها و collectionی از target model elementها را نمایش می‌دهد.

توصیف

directed relationship به یک یا چند source element و یک یا چند target element ارجاع می‌دهد. DirectedRelationship یک metaclass انتزاعی است.

Generalizationها

  • Relationship، صفحه 79

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • /source: Element[1..*] - sourceهای DirectedRelationship را مشخص می‌کند. زیرمجموعه Relationship::relatedElement و derived union است.
  • /target: Element[1..*] - targetهای DirectedRelationship را مشخص می‌کند. زیرمجموعه Relationship::relatedElement و derived union است.

Constraintها

هیچ constraint اضافی وجود ندارد.

معناشناسی

DirectedRelationship معناشناسی اختصاصی ندارد. subclassهای مختلف DirectedRelationship معناشناسی متناسب با مفهوم خود را اضافه می‌کنند.

نمادگذاری

برای DirectedRelationship notation عمومی وجود ندارد. subclassهای مشخص آن notation خود را تعریف می‌کنند. در بیشتر موارد notation گونه‌ای از خطی است که از source یا sourceها به target یا targetها رسم می‌شود.

9.17.2 Relationship

Relationship مفهومی انتزاعی است که نوعی رابطه میان elementها را مشخص می‌کند.

توصیف

relationship به یک یا چند related element ارجاع می‌دهد. Relationship یک metaclass انتزاعی است.

Generalizationها

  • Element (as specialized)، صفحه 74

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • /relatedElement: Element[1..*] - elementهایی را مشخص می‌کند که Relationship میان آن‌ها رابطه برقرار می‌کند. derived union است.

Constraintها

هیچ constraint اضافی وجود ندارد.

معناشناسی

Relationship معناشناسی اختصاصی ندارد. subclassهای مختلف Relationship معناشناسی مناسب مفهوم خود را اضافه می‌کنند.

نمادگذاری

برای Relationship notation عمومی وجود ندارد. subclassهای مشخص آن notation خود را تعریف می‌کنند. در بیشتر موارد notation گونه‌ای از خطی است که میان elementهای مرتبط رسم می‌شود.

9.18 package StructuralFeatures

package StructuralFeatures از package Abstractions یک generalization انتزاعی برای structural featureهای classifierها مشخص می‌کند.

شکل 9.45 - package StructuralFeatures
شکل 9.45 - package StructuralFeatures
شکل 9.46 - عناصر تعریف‌شده در package StructuralFeatures
شکل 9.46 - عناصر تعریف‌شده در package StructuralFeatures

9.18.1 StructuralFeature

structural feature یک typed feature از classifier است که ساختار instanceهای classifier را مشخص می‌کند.

توصیف

structural feature یک typed feature از classifier است که ساختار instanceهای classifier را مشخص می‌کند. StructuralFeature یک metaclass انتزاعی است.

Generalizationها

  • TypedElement، صفحه 86
  • Feature، صفحه 36

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

معناشناسی

structural feature مشخص می‌کند instanceهای featuring classifier دارای slotای هستند که value یا valueهای آن از type مشخصی‌اند.

نمادگذاری

نمادگذاری اضافی وجود ندارد.

9.19 package Super

package Super از package Abstractions سازوکارهایی برای مشخص‌کردن روابط generalization میان classifierها فراهم می‌کند.

شکل 9.47 - package Super
شکل 9.47 - package Super
شکل 9.48 - عناصر تعریف‌شده در package Super
شکل 9.48 - عناصر تعریف‌شده در package Super

9.19.1 Classifier (به‌صورت تخصصی‌شده)

توصیف

classifier می‌تواند با ارجاع به classifierهای عمومی خود یک generalization hierarchy را مشخص کند.

Generalizationها

  • Classifier، صفحه 35

Attributeها

  • isAbstract: Boolean - اگر true باشد، Classifier declaration کاملی ارائه نمی‌دهد و معمولاً قابل instantiate شدن نیست. classifier انتزاعی برای استفاده توسط classifierهای دیگر طراحی شده است؛ مثلاً به‌عنوان target مربوط به general metarelationship یا generalization relationship. مقدار پیش‌فرض false است.

Associationها

  • general: Classifier[*] - classifierهای عمومی‌تر این Classifier را در generalization hierarchy مشخص می‌کند.
  • /inheritedMember: NamedElement[*] - همه elementهایی را مشخص می‌کند که این classifier از classifierهای عمومی به ارث می‌برد. زیرمجموعه Namespace::member و derived است.

Constraintها

[1] generalization hierarchy باید directed و acyclic باشد. classifier نمی‌تواند هم‌زمان به‌صورت transitive هم general و هم specific همان classifier باشد.

not self.allParents()->includes(self)

[2] classifier فقط می‌تواند classifierهایی از type معتبر را specialization کند.

self.parents()->forAll(c | self.maySpecializeType(c))

[3] association با نام inheritedMember با به‌ارث‌بردن inheritable memberهای parentها مشتق می‌شود.

self.inheritedMember->includesAll(self.inherit(self.parents()->collect(p | p.inheritableMembers(self)))

Operationهای اضافی

[1] query با نام parents() تمام ancestorهای بلافصل یک Classifier generalizable را برمی‌گرداند.

Classifier::parents(): Set(Classifier);
parents = general

[2] query با نام allParents() همه ancestorهای مستقیم و غیرمستقیم Classifier generalizable را برمی‌گرداند.

Classifier::allParents(): Set(Classifier);
allParents = self.parents()->union(self.parents()->collect(p | p.allParents())

[3] query با نام inheritableMembers() همه memberهای classifier را که ممکن است با رعایت visibility restrictionهای مربوطه در یکی از descendantهای آن به ارث برسند برمی‌گرداند.

Classifier::inheritableMembers(c: Classifier): Set(NamedElement);
pre: c.allParents()->includes(self)
inheritableMembers = member->select(m | c.hasVisibilityOf(m))

[4] query با نام hasVisibilityOf() تعیین می‌کند یک named element در classifier visible هست یا خیر. به‌طور پیش‌فرض همه visible هستند. این query فقط وقتی فراخوانی می‌شود که argument چیزی باشد که در مالکیت یک parent قرار دارد.

Classifier::hasVisibilityOf(n: NamedElement) : Boolean;
pre: self.allParents()->collect(c | c.member)->includes(n)
if (self.inheritedMember->includes (n)) then
   hasVisibilityOf = (n.visibility <> #private)
else
   hasVisibilityOf = true

[5] query با نام inherit() نحوه inheritance یک مجموعه element را تعریف می‌کند. در اینجا operation به‌گونه‌ای تعریف شده که همه آن‌ها را به ارث ببرد. هدف آن است که در موقعیت‌هایی که redefinition روی inheritance اثر می‌گذارد بازتعریف شود.

Classifier::inherit(inhs: Set(NamedElement)): Set(NamedElement);
inherit = inhs

[6] query با نام maySpecializeType() تعیین می‌کند آیا این classifier می‌تواند با classifierهایی از type مشخص رابطه generalization داشته باشد یا خیر. به‌طور پیش‌فرض classifier می‌تواند classifierهای هم‌type یا type عمومی‌تر را تخصصی کند. classifierهایی که constraintهای تخصصی‌سازی متفاوت دارند باید این operation را بازتعریف کنند.

Classifier::maySpecializeType(c : Classifier) : Boolean;
maySpecializeType = self.oclIsKindOf(c.oclType)

معناشناسی

معناشناسی مشخص اینکه generalization چگونه روی هر subtype عینی Classifier اثر می‌گذارد متفاوت است.

یک instance از Classifier خاص به‌طور غیرمستقیم instanceی از هر Classifier عمومی نیز هست. بنابراین featureهای مشخص‌شده برای instanceهای classifier عمومی به‌طور ضمنی برای instanceهای classifier خاص نیز مشخص‌اند. هر constraintی که روی instanceهای classifier عمومی اعمال شود روی instanceهای classifier خاص نیز اعمال می‌شود.

نمادگذاری

نام Classifier انتزاعی به‌صورت italic نمایش داده می‌شود.

Generalization به‌شکل خطی با hollow triangle به‌عنوان arrowhead میان نمادهای classifierهای درگیر نمایش داده می‌شود. arrowhead به سمت classifier عمومی اشاره می‌کند. این notation «separate target style» نام دارد.

گزینه‌های ارائه

چند Classifier که classifier عمومی یکسانی دارند می‌توانند در «shared target style» کنار هم نمایش داده شوند.

یک Classifier انتزاعی را می‌توان با keyword {abstract} پس از یا زیر نام Classifier نمایش داد.

مثال‌ها

شکل 9.49 - نمونه hierarchy generalization کلاس‌ها:
شکل 9.49 - نمونه hierarchy generalization کلاس‌ها:

Shape classifier عمومی است و Polygon، Ellipse و Spline classifierهای تخصصی هستند؛ هر دو سبک separate target و shared target نمایش داده شده‌اند.

9.20 package TypedElements

subpackage TypedElements از package Abstractions، typed elementها و typeهای آن‌ها را تعریف می‌کند.

شکل 9.50 - package TypedElements
شکل 9.50 - package TypedElements
شکل 9.51 - عناصر تعریف‌شده در package TypedElements
شکل 9.51 - عناصر تعریف‌شده در package TypedElements

9.20.1 Type

type روی valueهای نمایش‌داده‌شده توسط typed element قید اعمال می‌کند.

توصیف

type به‌عنوان قیدی روی دامنه valueهایی که توسط typed element نمایش داده می‌شوند عمل می‌کند. Type یک metaclass انتزاعی است.

Generalizationها

  • NamedElement، صفحه 71

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

هیچ constraint اضافی وجود ندارد.

Operationهای اضافی

[1] query با نام conformsTo() برای typeای که با type دیگر conform است true برمی‌گرداند. به‌طور پیش‌فرض دو type با یکدیگر conform نیستند. این query برای بازتعریف در وضعیت‌های conformance مشخص طراحی شده است.

conformsTo(other: Type): Boolean;
conformsTo = false

معناشناسی

یک type مجموعه‌ای از valueها را نمایش می‌دهد. typed elementای که این type را دارد فقط می‌تواند valueهای درون این مجموعه را نمایش دهد.

نمادگذاری

نمادگذاری عمومی وجود ندارد.

9.20.2 TypedElement

typed element دارای type است.

توصیف

typed element عنصری است که type آن به‌عنوان قیدی روی دامنه valueهایی عمل می‌کند که element می‌تواند نمایش دهد. TypedElement یک metaclass انتزاعی است.

Generalizationها

  • NamedElement، صفحه 71

Attributeها

هیچ attribute اضافی وجود ندارد.

Associationها

  • type: Type[0..1] - type مربوط به TypedElement.

Constraintها

هیچ constraint اضافی وجود ندارد.

معناشناسی

valueهای نمایش‌داده‌شده توسط element باید instanceهایی از type باشند. typed elementای که type وابسته ندارد می‌تواند valueهایی از هر type را نمایش دهد.

نمادگذاری

نمادگذاری عمومی وجود ندارد.

9.21 package Visibilities

subpackage Visibility از package Abstractions سازه‌های بنیادی‌ای فراهم می‌کند که بر پایه آن‌ها می‌توان معناشناسی visibility را ساخت.

شکل 9.52 - package Visibilities
شکل 9.52 - package Visibilities
شکل 9.53 - عناصر تعریف‌شده در package Visibilities
شکل 9.53 - عناصر تعریف‌شده در package Visibilities

9.21.1 NamedElement (به‌صورت تخصصی‌شده)

توصیف

NamedElement دارای attribute با نام visibility است.

Attributeها

  • visibility: VisibilityKind[0..1] - تعیین می‌کند NamedElement در Namespaceهای مختلف model کلی در کجا ظاهر شود و میزان دسترسی به آن چگونه باشد.

Generalizationها

  • NamedElement، صفحه 71

Associationها

هیچ association اضافی وجود ندارد.

Constraintها

[1] اگر NamedElement در مالکیت Namespace نباشد، visibility ندارد.

namespace->isEmpty() implies visibility->isEmpty()

معناشناسی

attribute visibility امکان محدودکردن استفاده از named element را، چه در namespaceها و چه در دسترسی به element، فراهم می‌کند. این attribute برای استفاده همراه با سازوکارهای import، generalization و access طراحی شده است.

9.21.2 VisibilityKind

VisibilityKind یک enumeration type است که literalهایی را برای تعیین visibility elementها در model تعریف می‌کند.

Generalizationها

هیچ‌کدام.

توصیف

VisibilityKind enumerationی با literal valueهای زیر است:

  • public
  • private
  • protected
  • package

Operationهای اضافی

[1] query با نام bestVisibility() مجموعه‌ای از VisibilityKindها را بررسی می‌کند و public را به‌عنوان visibility ترجیحی برمی‌گرداند.

VisibilityKind::bestVisibility(vis: Set(VisibilityKind)) : VisibilityKind;
bestVisibility = if vis->includes(#public) then #public else #private endif

معناشناسی

VisibilityKind برای استفاده در مشخصه‌سازی visibility همراه با packageهایی مانند Imports، Generalizations، Packages و Classifiers طراحی شده است. معناشناسی تفصیلی در همان سازوکارها مشخص می‌شود. اگر package Visibility بدون آن packageها استفاده شود، این literalها ممکن است معنای متفاوتی داشته باشند یا اصلاً معنایی نداشته باشند.

  • element با visibility public برای تمام elementهایی visible است که بتوانند به محتوای namespace مالک آن دسترسی داشته باشند.
  • element با visibility private فقط درون namespace مالک خود visible است.
  • element با visibility protected برای elementهایی visible است که با namespace مالک آن رابطه generalization دارند.
  • element با visibility package در مالکیت namespaceای است که package نیست و برای elementهایی visible است که در همان package مربوط به owning namespace قرار دارند. فقط named elementهایی که در مالکیت package نیستند می‌توانند package visibility داشته باشند. هر element با package visibility برای همه elementهای درون نزدیک‌ترین enclosing package visible است، مشروط بر اینکه سایر owning elementها visibility مناسب داشته باشند. بیرون از نزدیک‌ترین enclosing package، element دارای package visibility visible نیست.

در شرایطی که named element در نهایت چند visibility داشته باشد، مثلاً به‌دلیل import شدن چندباره، visibility عمومی بر private غلبه می‌کند. برای مثال اگر element دو بار به یک namespace import شود، یک بار با public import و بار دیگر با private import، نتیجه public خواهد بود.

نمادگذاری

گزینه‌های نمایش بصری زیر برای literal valueهای enumeration با نام VisibilityKind در دسترس‌اند:

نماد Visibility
+ public
- private
# protected
~ package

امتیاز کاربران به این مقاله

☆☆☆☆☆

0 نفر امتیاز داده اند. میانگین: 0.0 از 5

 

0 نظر

نظر محترم شما در مورد مقاله های وب سایت برنامه نویسی و پایگاه داده

نظرات محترم شما در خدمات رسانی بهتر ما را یاری می نمایند. لطفا اگر مایل بودید یک نظر ما را مهمان فرمائید. آدرس ایمیل و وب سایت شما نمایش داده نخواهد شد.

0 / 500

اطلاعات تماس

  • آدرس:اصفهان-خیابان ام کلثوم غربی - بعد خیابان تخم چی - بیست متر بعد از پیتزا ننه شب - کوچه تعمیر گاه سمار زغالی - پلاک 354 - درب مشکی - طبقه هفتم
  • آدرس ایمیل:najafzade@gmail.com
  • وب سایت:http://www.a00b.com/
  • تلفن ثابت:(+98)9131253620
  • تلفن همراه:09131253620