آموزش سیلورلایت 4 - قسمتهای 21 تا 27
در یک پروژه WCF RIA Services کلیه اعمال کار با بانک اطلاعاتی در همان سمت سرور و توسط سرویسهایی که اضافه میکنید انجام خواهد شد. فقط صدا زدن متدهای این سرویسها است که در سمت کاربر و برنامه سیلولایتی صورت خواهد گرفت (در همان ViewModel).
از آنجائیکه قسمت عمده مدل سیستم حین نمایش از همان جداول بانک اطلاعاتی شما تشکیل خواهد شد که در سمت سرور در سرویسهای تعریف شده قابل دسترسی میشود، روش WCF RIA Services تعریف مجدد اینها را در سمت کاربر به صورت خودکار انجام میدهد. به همراه replicate کردن تمام مسایل اعتبار سنجی و غیره به سمت کاربر.
معماری اطلاعات یا Information Architecture و یا به اختصار IA در یک تیم توسعه نرمافزار، یک وظیفه پایه و اساسی است که معمولا بین طراحان، توسعه دهندگان و یا طراحان استراتژی محتوا تقسیم میگردد. اما صرف نظر از اینکه چه کسی در یک تیم آن را بر عهده میگیرد، IA تخصص خاص خود را نیازمند است که این تخصص که شامل ابزارها و شاخصها و منابعی است که باید به درستی تحقیق و گردآوری گردند. در این مقاله قصد داریم تا به این امر بپردازیم که واقعا IA چیست؟ و چرا یک جنبهی مهم و ارزشمند در طراحی فرآیندهای user experience به شمار میرود؟
Information Architecture چیست؟
بیان کردن یک تعریف دقیق برای IA کمی پیچیدهتر از تعاریف دیگری همچون content strategy و یا interaction design به نظر میرسد. بر خلاف content strategy که به وسیله طراحان استراتژی محتوا و یا interaction design که توسط طراحان UI/UX انجام میگیرد، IA به ندرت در زمرهی یک کار جداگانه قرار میگیرد. اما با این وجود، این کار در مهندسی نرم افزار بسیار با ارزش و لازم محسوب میگردد. (منبع)
بر اساس تعریف ویکیپدیا، IA اینگونه تعریف میگردد: "معماری اطلاعات عبارت است از طراحی ساختاری سامانههای اشتراک اطلاعات، که با هدف یافت پذیری و کاربرد پذیری انجام میشود."
در فرهنگ معماری اطلاعات، مفهوم یافتپذیری یا Findability به زبان ساده، شاخصی است که قابلیت یافت شدن و مکانیابی یک مجموعه اطلاعات را محک میزند. به عنوان مثال سامانههای اطلاعرسانی مانند وب سایتها باید به گونهای طراحی شوند که مردم در هر سطحی، به سادگی بتوانند اطلاعات مورد نظر خود را پیدا کنند.
مفهوم کاربردپذیری یا Usability ، شاخصهای است که میزان سهولت کاربری یک ابزار را نشان میدهد. این تعریف را میتوان به این صورت کامل نمود: "میزانی که یک محصول میتواند توسط کاربران خاصی برای رسیدن به هدفی مشخص مورد استفاده قرار گیرد و در حین استفاده، ضمن داشتن اثربخشی و کارآیی، رضایت کاربر را در زمینه مورد استفاده تامین کند." به عنوان مثال هنگامیکه شما قصد خرید اینترنتی را داشته باشید، در درجه اول مفهوم یافتپذیری برای شما پررنگ خواهد شد و پس از آن با انجام خرید حس کاربردپذیری فروشگاه خواهد بود که برای دفعات بعدی شما را به آن وبسایت هدایت خواهد کرد.
بنا بر آنچه که گفته شد، مفهوم یافتپذیری مقدم بر کاربردپذیری است. یعنی اگر کاربر نتواند آنچه را که به دنبال آن است بیابد، هرگز فرصت استفاده از آنرا نخواهد داشت. به علاوه اگر یافتپذیری محقق شود، کاربردپذیری هم بهبود خواهد یافت، چرا که مردم میتوانند به سرعت و سهولت به آنچه که نیاز دارند دست یابند. ذکر این نکته نیز حائز اهمیت است که موتورهای جست و جو، تنها وظیفهی هدایت کاربران را به وبسایت هدف خواهند داشت. اما وظیفه یافت پذیری، با بازدید کاربران از وبسایت آغاز میگردد. به نوعی میتوان گفت که یافتپذیری میکوشد به مردم این امکان را بدهد تا در هنگام گذار در وبسایت، به اطلاعاتی که نیاز دارند دست یابند.
معماری اطلاعات یکی از مهمترین مراحل توسعهی نرمافزار، به خصوص توسعهی نرمافزارهای تحت وب به شمار میرود. در حقیقت با انجام معماری اطلاعات دقیق، میتوان مواردی از قبیل رسیدن به اهداف تعیین شده، کم کردن هزینهی نگهداری و به روز رسانی، افزایش کارآیی و در نهایت کم شدن ریسکها را مدیریت نمود.
بر اساس آنچه که در وبسایت UXmatters و webmonkey گفته شده است، IA در شش مرحله صورت میگیرد:
1. ارزیابی هدف کسب و کار ( Assess business intent )
2. ارزیابی هدف کاربران ( Assess user intent )
3. ارزیابی محتوا ( Assess content )
4. مدیریت محتوا ( Organize content )
5. برقرارسازی ارتباط میان اطلاعات ( Enable information relationships )
6. فراهمسازی فرآیند هدایت محتوا ( Provide navigation )
تصویر زیر که برگرفته از وبسایت SitePoint میباشد برخی از مراحل فوق را به صورت مختصر و ساده نمایش داده است.
اگر به وبسایت رسمی انجمن معماری اطلاعات سری بزنید مطالب مفیدی در زمینهی پیاده سازی IA به دست خواهید آورد.
تصویر زیر ارتباط تنگاتنگ سه مبحث Information Design ، Interaction Design و Sensorial Design را نمایش میدهد. همانطور که میبینید، محتوا در مرکزیت هر سه موضوع قرار دارد. بنابراین میتوان اینگونه استنباط کرد که محتوا اصلیترین بخش یک کسبوکار نرمافزاری را تشکیل میدهد. اما در بخش پیشین دیدیم که محتوا به تنهایی نمیتواند راهگشای نتیجهی عالی از یک نرمافزار باشد. با توجه به دو مفهوم یافتپذیری و کاربردپذیری دیدیم برای آنکه بتوانیم در تولید نرمافزار بهترین باشیم، بایستی در قدم اول مفهوم یافتپذیری را رعایت نماییم. به زبان ساده باید هر چیزی را در جای مورد نظر خود قرار دهیم تا کاربر در مدت زمان خیلی کمی بتواند به آن دسترسی داشته باشد.
همانطور که در تصویر فوق ملاحظه میکنید دو اصطلاح شاید نا آشنای دیگر نیز آورده شده است، Interaction Design و Sensorial Design. در مقالهای دیگر به آنها خواهیم پرداخت.
EF Code First #12
- جهت مدیریت سادهتر کار، بهتر است هر کدام از موجودیتها یک کلاس سرویس مجزا داشته باشند. ضمنا در دنیای واقعی در بسیاری از اوقات نیاز است این کلاسهای سرویس با چندین موجودیت جهت برآورده ساختن یک منطق تجاری کار کنند. بنابراین محدود کردن آنها به T عملا پاسخ نخواهد داد.
- پیشتر هم در نظرات قبلی عنوان شده، نمونهی پروژهی خوب در این مورد، سیستم مدیریت محتوای IRIS است که مطالعهی کدهای آن میتواند دید بهتری به شما بدهد.
تدارک مقدمات مثال این قسمت
این مثال، در ادامهی همین سری کار با فرمهای مبتنی بر قالبها است. به همین جهت ابتدا ماژول جدید CustomValidators را به آن اضافه میکنیم:
>ng g m CustomValidators -m app.module --routing
>ng g c CustomValidators/user-register
در ادامه کلاس مدل معادل فرم ثبت نام کاربران را تعریف میکنیم:
>ng g cl CustomValidators/user
export class User { constructor( public username: string = "", public email: string = "", public password: string = "", public confirmPassword: string = "" ) {} }
- ورود نام کاربری اجباری بوده و باید بین 5 تا 8 حرف باشد.
- ورود ایمیل اجباری بوده و باید فرمت مناسبی نیز داشته باشد.
- ورود کلمهی عبور اجباری بوده و باید با confirmPassword تطابق داشته باشد.
- ورود «کلمهی عبور خود را مجددا وارد کنید» اجباری بوده و باید با password تطابق داشته باشد.
تعریف اعتبارسنج سفارشی ایمیلها
هرچند میتوان اعتبارسنجی ایمیلها را توسط ویژگی استاندارد pattern نیز مدیریت کرد، اما جهت بررسی نحوهی انتقال آن به یک اعتبارسنج سفارشی، کار را با ایجاد یک دایرکتیو مخصوص آن ادامه میدهیم:
>ng g d CustomValidators/EmailValidator -m custom-validators.module
در ادامه کدهای کامل این اعتبارسنج سفارشی را مشاهده میکنید:
import { Directive } from "@angular/core"; import { AbstractControl, NG_VALIDATORS, Validator } from "@angular/forms"; @Directive({ selector: "[appEmailValidator][formControlName],[appEmailValidator][formControl],[appEmailValidator][ngModel]", providers: [ { provide: NG_VALIDATORS, useExisting: EmailValidatorDirective, multi: true } ] }) export class EmailValidatorDirective implements Validator { validate(element: AbstractControl): { [key: string]: any } { const emailRegex = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; const valid = emailRegex.test(element.value); return valid ? null : { appEmailValidator: true }; } }
- علت تعریف این اعتبارسنج به صورت یک دایرکتیو جدید این است که بتوان selector آنرا همانند ویژگیهای HTML، به فیلد ورودی اضافه کرد:
<input #email="ngModel" required appEmailValidator type="text" class="form-control" name="email" [(ngModel)]="model.email">
- روش تعریف selector آن اندکی متفاوت است:
selector: "[appEmailValidator][formControlName],[appEmailValidator][formControl],[appEmailValidator][ngModel]",
الف) نام دایرکتیو باید با یک پیشوند شروع شود و این پیشوند در فایل angular-cli.json. به app تنظیم شدهاست:
"apps": [ { // ... "prefix": "app",
ب) در اینجا formControlName، formControl و ngModel قید شدهی در کنار نام selector این دایرکتیو را نیز مشاهده میکنید. وجود آنها به این معنا است که کلاس این دایرکتیو، به المانهایی که به آنها ویژگی appEmailValidator اضافه شدهاست و همچنین آن المانها از یکی از سه نوع ذکر شده هستند، اعمال میشود و در سایر موارد بیاثر خواهد بود. البته ذکر این سه نوع، اختیاری است و صرفا میتوان نوشت:
selector: "[appEmailValidator]"
- پس از آن قسمت providers را مشاهده میکنید:
providers: [ { provide: NG_VALIDATORS, useExisting: EmailValidatorDirective, multi: true }
- سپس پیاده سازی اینترفیس توکار Validator را مشاهده میکنید:
export class EmailValidatorDirective implements Validator {
برای پیاده سازی این اینترفیس، نیاز است متد اجباری ذیل را نیز افزود و تکمیل کرد:
validate(element: AbstractControl): { [key: string]: any }
validate(element: AbstractControl): { [key: string]: any } { const emailRegex = /\w+([-+.']\w+)*@\w+([-.]\w+)*\.\w+([-.]\w+)*/; const valid = emailRegex.test(element.value); return valid ? null : { appEmailValidator: true }; }
- اکنون که این دایرکتیو جدید طراحی و ثبت شدهاست (در قسمت declarations فایل custom-validators.module.ts)، تنها کافی است selector آنرا به المان ورودی مدنظر اعمال کنیم تا کار اعتبارسنجی آنرا به صورت خودکار مدیریت کند:
<input #email="ngModel" required appEmailValidator type="text" class="form-control" name="email" [(ngModel)]="model.email">
نحوهی طراحی خروجی متد validate
هنگام پیاده سازی متد validate اینترفیس Validator، هیچ قالب خاصی برای خروجی آن درنظر گرفته نشدهاست و همینقدر که این خروجی یک شیء key/value باشد، کفایت میکند. برای مثال اگر اعتبارسنج استاندارد required با شکست مواجه شود، یک چنین شیءایی را بازگشت میدهد:
{ required:true }
{ minlength : { requiredLength : 3, actualLength : 1 } }
{ appEmailValidator: true }
<div class="alert alert-danger" *ngIf="email.errors.appEmailValidator"> The entered email is not valid. </div>
از دیدگاه اعتبارسنج فرمهای مبتنی بر قالبها، همینقدر که آرایهی email.errors دارای عضو و کلید جدیدی شد، کار به پایان رسیدهاست و اعتبارسنجی المان را شکست خورده ارزیابی میکند. مابقی آن، اطلاعاتی است که برنامه نویس ارائه میدهد (بر اساس نیازهای نمایشی برنامه).
تهیه اعتبارسنج سفارشی مقایسهی کلمات عبور با یکدیگر
در طراحی کلاس User که معادل فیلدهای فرم ثبت نام کاربران است، دو خاصیت کلمهی عبور و تائید کلمهی عبور را مشاهده میکنید:
public password: string = "", public confirmPassword: string = ""
>ng g d CustomValidators/EqualValidator -m custom-validators.module
در ادامه کدهای کامل آنرا در ذیل مشاهده میکنید:
import { Directive, Attribute } from "@angular/core"; import { Validator, AbstractControl, NG_VALIDATORS } from "@angular/forms"; @Directive({ selector: "[appValidateEqual][formControlName],[appValidateEqual][formControl],[appValidateEqual][ngModel]", providers: [ { provide: NG_VALIDATORS, useExisting: EqualValidatorDirective, multi: true } ] }) export class EqualValidatorDirective implements Validator { constructor(@Attribute("compare-to") public compareToControl: string) {} validate(element: AbstractControl): { [key: string]: any } { const selfValue = element.value; const otherControl = element.root.get(this.compareToControl); console.log("EqualValidatorDirective", { thisControlValue: selfValue, otherControlValue: otherControl ? otherControl.value : null }); if (otherControl && selfValue !== otherControl.value) { return { appValidateEqual: true // Or a string such as 'Password mismatch.' or an abject. }; } if ( otherControl && otherControl.errors && selfValue === otherControl.value ) { delete otherControl.errors["appValidateEqual"]; if (!Object.keys(otherControl.errors).length) { otherControl.setErrors(null); } } return null; } }
- قسمت آغازین این اعتبارسنج سفارشی، مانند توضیحات EmailValidatorDirective است که در ابتدای بحث عنوان شد. این کلاس به یک Directive مزین شدهاست تا بتوان selector آنرا به المانهای HTML ایی فرم افزود (برای مثال در اینجا به دو فیلد ورود کلمات عبور). قسمت providers آن نیز تنظیم شدهاست تا EqualValidatorDirective جاری به لیست توکار NG_VALIDATORS اضافه شود.
- در ابتدای کار، پیاده سازی اینترفیس Validator، همانند قبل انجام شدهاست؛ اما چون در اینجا میخواهیم نام فیلدی را که قرار است کار مقایسه را با آن انجام دهیم نیز دریافت کنیم، ابتدا یک Attribute و سپس یک پارامتر و خاصیت عمومی دریافت کنندهی مقدار آنرا نیز افزودهایم:
export class EqualValidatorDirective implements Validator { constructor(@Attribute("compare-to") public compareToControl: string) {}
<input #password="ngModel" required type="password" class="form-control" appValidateEqual compare-to="confirmPassword" name="password" [(ngModel)]="model.password">
در اینجا محدودیتی هم از لحاظ تعداد ویژگیها نیست و اگر قرار است این اعتبارسنج اطلاعات بیشتری را نیز دریافت کند میتوان ویژگیهای بیشتری را به سازندهی آن نسبت داد.
یک نکته: میتوان نام این ویژگی را با نام selector نیز یکی انتخاب کرد. به این ترتیب ذکر نام ویژگی آن، هم سبب فعال شدن اعتبارسنج و هم نسبت دادن مقداری به آن، سبب مقدار دهی خاصیت متناظر با آن، در سمت کلاس اعتبارسنج میگردد.
- در ابتدای این اعتبارسنج، نحوهی دسترسی به مقدار یک کنترل دیگر را نیز مشاهده میکنید:
export class EqualValidatorDirective implements Validator { constructor(@Attribute("compare-to") public compareToControl: string) {} validate(element: AbstractControl): { [key: string]: any } { const selfValue = element.value; const otherControl = element.root.get(this.compareToControl); console.log("EqualValidatorDirective", { thisControlValue: selfValue, otherControlValue: otherControl ? otherControl.value : null });
بر اساس مقدار خاصیت compareToControl که از ویژگی compare-to دریافت میشود، میتوان به کنترل دوم، توسط element.root.get دسترسی یافت.
- در ادامهی کار، مقایسهی سادهای را مشاهده میکنید:
if (otherControl && selfValue !== otherControl.value) { return { appValidateEqual: true // Or a string such as 'Password mismatch.' or an abject. }; }
- در پایان کدهای متد validate، چنین تنظیمی نیز قرار گرفتهاست:
if (otherControl && otherControl.errors && selfValue === otherControl.value) { delete otherControl.errors["appValidateEqual"]; if (!Object.keys(otherControl.errors).length) { otherControl.setErrors(null); } } return null;
تکمیل کامپوننت فرم ثبت نام کاربران
اکنون user-register.component.ts را که در ابتدای بحث اضافه کردیم، چنین تعاریفی را پیدا میکند:
import { NgForm } from "@angular/forms"; import { User } from "./../user"; import { Component, OnInit } from "@angular/core"; @Component({ selector: "app-user-register", templateUrl: "./user-register.component.html", styleUrls: ["./user-register.component.css"] }) export class UserRegisterComponent implements OnInit { model = new User(); constructor() {} ngOnInit() {} submitForm(form: NgForm) { console.log(this.model); console.log(form.value); } }
ابتدای فرم
<div class="container"> <h3>Registration Form</h3> <form #form="ngForm" (submit)="submitForm(form)" novalidate>
تکمیل قسمت ورود نام کاربری
<div class="form-group" [class.has-error]="username.invalid && username.touched"> <label class="control-label">User Name</label> <input #username="ngModel" required maxlength="8" minlength="4" type="text" class="form-control" name="username" [(ngModel)]="model.username"> <div *ngIf="username.invalid && username.touched"> <div class="alert alert-info"> errors: {{ username.errors | json }} </div> <div class="alert alert-danger" *ngIf="username.errors.required"> username is required. </div> <div class="alert alert-danger" *ngIf="username.errors.minlength"> username should be minimum {{username.errors.minlength.requiredLength}} characters. </div> <div class="alert alert-danger" *ngIf="username.errors.maxlength"> username should be max {{username.errors.maxlength.requiredLength}} characters. </div> </div> </div>
تکمیل قسمت ورود ایمیل
<div class="form-group" [class.has-error]="email.invalid && email.touched"> <label class="control-label">Email</label> <input #email="ngModel" required appEmailValidator type="text" class="form-control" name="email" [(ngModel)]="model.email"> <div *ngIf="email.invalid && email.touched"> <div class="alert alert-info"> errors: {{ email.errors | json }} </div> <div class="alert alert-danger" *ngIf="email.errors.required"> email is required. </div> <div class="alert alert-danger" *ngIf="email.errors.appEmailValidator"> The entered email is not valid. </div> </div> </div>
تکمیل قسمتهای ورود کلمهی عبور و تائید آن
<div class="form-group" [class.has-error]="password.invalid && password.touched"> <label class="control-label">Password</label> <input #password="ngModel" required type="password" class="form-control" appValidateEqual compare-to="confirmPassword" name="password" [(ngModel)]="model.password"> <div *ngIf="password.invalid && password.touched"> <div class="alert alert-info"> errors: {{ password.errors | json }} </div> <div class="alert alert-danger" *ngIf="password.errors.required"> password is required. </div> <div class="alert alert-danger" *ngIf="password.errors.appValidateEqual"> Password mismatch. Please complete the confirmPassword . </div> </div> </div> <div class="form-group" [class.has-error]="confirmPassword.invalid && confirmPassword.touched"> <label class="control-label">Retype password</label> <input #confirmPassword="ngModel" required type="password" class="form-control" appValidateEqual compare-to="password" name="confirmPassword" [(ngModel)]="model.confirmPassword"> <div *ngIf="confirmPassword.invalid && confirmPassword.touched"> <div class="alert alert-info"> errors: {{ confirmPassword.errors | json }} </div> <div class="alert alert-danger" *ngIf="confirmPassword.errors.required"> confirmPassword is required. </div> <div class="alert alert-danger" *ngIf="confirmPassword.errors.appValidateEqual"> Password mismatch. </div> </div> </div>
همچنین خروجی آن نیز در قسمت ngIf آخر بررسی شدهاست و سبب نمایش خطای اعتبارسنجی متناسبی میشود.
تکمیل انتهای فرم
<button class="btn btn-primary" [disabled]="form.invalid" type="submit">Ok</button> </form> </div>
کدهای کامل این قسمت را از اینجا میتوانید دریافت کنید: angular-template-driven-forms-lab-08.zip
برای اجرای آن فرض بر این است که پیشتر Angular CLI را نصب کردهاید. سپس به ریشهی پروژه وارد شده و دو پنجرهی کنسول مجزا را باز کنید. در اولی دستورات
>npm install >ng build --watch
>dotnet restore >dotnet watch run
خلاصهای کوتاه در مورد WinRT
- از این جهت که رابطهای کاربری مبتنی بر WinRT ، یا بر پایه XAML است یا HTML/CSS ، یادگیری WPF و یا سیلورلایت (که قسمتی از WPF را به ارث برده) مفید خواهند بود؛ از این لحاظ که پایه رابط کاربری هر دوی اینها هم XAML است و اساسا طراحی XAML از اینجا به WinRT منتقل شده.
کلا برای برنامه نویسهای دات نت WinRT مثل یک سری اسمبلی جدید است که اضافه شده و یک سری اسمبلی از آنها گرفته شده. هیچ تفاوت دیگری از لحاظ اصول برنامه نویسی نمیکند. یک سری فضای نام جدید و کلاس جدید دارید. یک سری از کلاسهای پیشین به دلیل محدودیتهای امنیتی، دیگر در WinRT قابل استفاده نیست. مثلا همینطوری دیگه نمیتونید هر جایی فایل جدید درست کنید، یک سری آداب و اصول خاص خودش را دارد.
ضمنا این رو هم در نظر داشته باشید که WinRT یک سیستم همه منظوره نیست و ... بین خودمان باشد بیشتر در سطح دسکتاپ برای کارهای شیک و چشم نواز و برنامههای فانتزی طراحی شده. اصل کارهای برنامههای تجاری باز هم بر اساس همان سیستمهای وب و یا دسکتاپ سابق خواهد بود.
- یادگیری سی++ همیشه مفید است. حتی در کره مریخ هم تاجایی که اطلاع دارم (!) یک کامپایلر سی++ وجود دارد و میشود با آن برنامهی Hello world را کامپایل کرد. اگر باور ندارید از این لینوکسیها بپرسید!
Today, we’re announcing that Microsoft 365 apps and services will no longer support Internet Explorer 11 (IE 11) by this time next year.
- Beginning November 30, 2020, the Microsoft Teams web app will no longer support IE 11.
- Beginning August 17, 2021, the remaining Microsoft 365 apps and services will no longer support IE 11.
متدهای احراز هویت در VS 2013
اگر از IE استفاده کنید، مشکلی نباید باشه. چون IE با سیستم اعتبارسنجی مبتنی بر ویندوز یکپارچه هست. اگر با IE صفحه لاگین مرورگر باز میشه، به تنظیمات امنیتی اون مراجعه کنید و سایت رو در قسمت trusted sites اضافه کنید: http://support.microsoft.com/kb/258063
سمت سرور هم باید در تنظیمات IIS، گزینهی اعتبارسنجی مبتنی بر ویندوز فعال باشه:
public class DocumentPrinter { public void PrintDocument(string documentName) { var repository = new DocumentRepository(); var formatter = new DocumentFormatter(); var printer = new Printer(); var document = repository .GetDocumentByName(documentName); var formattedDocument = formatter.Format(document); printer.Print(formattedDocument); } }
var documentPrinter = new DocumentPrinter(); documentPrinter.PrintDocument(@"c:\doc.doc");
public class DocumentPrinter { private DocumentRepository _repository; private DocumentFormatter _formatter; private Printer _printer; public DocumentPrinter( DocumentRepository repository, DocumentFormatter formatter, Printer printer) { _repository = repository; _formatter = formatter; _printer = printer; } public void PrintDocument(string documentName) { var document = _repository.GetDocumentByName(documentName); var formattedDocument = _formatter.Format(document); _printer.Print(formattedDocument); } }
var repository = new DocumentRepository(); var formatter = new DocumentFormatter(); var printer = new Printer(); var documentPrinter = new DocumentPrinter(repository, formatter, printer); documentPrinter.PrintDocument(@"c:\doc.doc");
public interface IDocumentRepository { Document GetDocumentByName(string documentName); }
public class DocumentPrinter { private IDocumentRepository _repository; private IDocumentFormatter _formatter; private IPrinter _printer; public DocumentPrinter( IDocumentRepository repository, IDocumentFormatter formatter, IPrinter printer) { _repository = repository; _formatter = formatter; _printer = printer; } public void PrintDocument(string documentName) { var document = _repository.GetDocumentByName(documentName); var formattedDocument = _formatter.Format(document); _printer.Print(formattedDocument); } }
ObjectFactory.Configure(cfg => { cfg.For<IDocumentRepository>().Use<FilesystemDocumentRepository>(); cfg.For<IDocumentFormatter>().Use<DocumentFormatter>(); cfg.For<IPrinter>().Use<Printer>(); });