In .NET 8 we plan to add a new project template, Blazor
Web Application, that covers all combinations of server-hosted projects
(traditional Blazor Server apps, Blazor WebAssembly hosted, and the new
unified architecture that allows use of Server, WebAssembly, and SSR in a
single project). It will work by multitargeting over net8.0
and net8.0-browser
.
The tutorials in this repository are:
کار این کلاس در واقع ترکیب کلاسها و کتابخانههای کاری مشخص است که نیاز به ارتباط با یکدیگر را دارند. به عنوان مثال یک برنامه کتابخانه، برای وظیفهای چون امانت یک کتاب نیاز است تا چندین کلاس مختلف را با یکدیگر به کار بگیرد که این وظایف شامل موارد زیر میباشند:
- بررسی وجود کتاب
- بررسی تعداد موجود یک کتاب در کتابخانه
- بررسی وضعیت امانی کتاب (آیا کتاب در دست کسی از قبل امانت است؟ یا کتاب برای امانت آزاد است؟)
- در صورتی که کتابی بیش از زمان مورد نظر در دست کسی امانت است، با یک پیامک از او بخواهیم که کتاب را بازگرداند.
در کد زیر ما قصد داریم نمونهای از اجرای این الگو را ببینیم. ابتدا سه کلاس اطلاعاتی زیر را ایجاد میکنیم:
کلاس کتاب Book:
class Book { public int Id { get; set; } public string Title { get; set; } public int Quantity { get; set; } public bool IsLoanable { get; set; } }
کلاس کاربر User
class User { public int Id { get; set; } public string Title { get; set; } public string CellPhoneNumber { get; set; } }
کلاس امانت Loan
class Loan { public DateTime ExpiredDate { get; set; } public User User { get; set; } }
بعد از آن سه کلاس را برای مدیریت کتاب، مدیریت امانت و مدیریت پیامکی، ایجاد میکنیم:
کلاس کتاب BookManager:
class BookManager { public Book GetBook(int id) { return new Book() { Id=id, Title = "a book", Quantity = 3, IsLoanable = true }; } }
کلاس LoanManager برای مدیریت امانتها
public int IsLoan(int bookId) { return 2; } public List<Loan> GetLoans(int bookId) { return new List<Loan>() { new Loan() { ExpiredDate = DateTime.Now.AddDays(-15), User = new User() { Id = 2, Title = "User1", CellPhoneNumber = "342342424" } }, new Loan() { ExpiredDate = DateTime.Now.AddDays(5), User = new User() { Id = 56, Title = "User56", CellPhoneNumber = "324324324324" } } }; }
در نهایت سومی کلاس مدیریتی برای پیامک هاست:
class SmsManager { public void SendMessage(string number) { Console.WriteLine("please take back the book to the library : "+number); } }
و در کلاس Facade داریم
class FacadeBookLoan { private readonly BookManager _bookManager; private readonly LoanManager _loanManager; private readonly SmsManager _smsManager; public FacadeBookLoan() { _bookManager = new BookManager(); _loanManager=new LoanManager(); _smsManager=new SmsManager(); } public int IsLoanable(int bookId) { var book = _bookManager.GetBook(2); if (book == null) return -2; if (!book.IsLoanable) return -1; var howManyBookIsLoaned = _loanManager.IsLoan(bookId); if(howManyBookIsLoaned>0) ManageLoaners(bookId); return book.Quantity - howManyBookIsLoaned; } private void ManageLoaners(int bookId) { var loans = _loanManager.GetLoans(bookId); foreach (var loan in loans) { if (loan.ExpiredDate > DateTime.Now) { _smsManager.SendMessage(loan.User.CellPhoneNumber); } } } }
کد بدنه اصلی برنامه:
var myfacade=new FacadeBookLoan(); var loansCount= myfacade.IsLoanable(2); Console.WriteLine(loansCount > 0 ? "you can loan the book" : "you can't loan the book");
please take back the book to the library : 324324324324 you can loan the book
Memento یک الگوی طراحی مفید و ساده است که برای ذخیره و بازیابی state یک object استفاده میشود. در بعضی از مقالات از آن به عنوان snapshot نیز یاد شده است! اگر با git کار کرده باشید، این مفهوم را میتوان در git بسیار یافت؛ هر commit به عنوان یک snapshot میباشد که میتوان به صورت مکرر آن را undo کرد و یا مثال خیلی سادهتر میتوان به ctrl+z در سیستم عامل اشاره کرد.
به مثال زیر توجه کنید:
Int temp; Int a=1; temp=a; a=2; . . a=temp;
شما قطعا در برنامه نویسی با کد بالا زیاد برخورد داشتهاید و آنرا به صورت مکرر انجام دادهاید. کد بالا را در قالب یک object بیان میکنیم. به مثال زیر توجه کنید:
int main() { MyClass One = new MyClass(); MyClass Temp = new MyClass(); // Set an initial value. One.Value = 10; One.Name = "Ten"; // Save the state of the value. Temp.Value = One.Value; Temp.Name = One.Name; // Change the value. One.Value = 99; One.Name = "Ninety Nine"; // Undo and restore the state. One.Value = Temp.Value; One.Name = Temp.Name; }
در کد بالا با استفاده از یک temp، شیء مورد نظر را ذخیره کرده و در آخر مجدد دادهها را درون شیء، restore میکنیم.
از مشکلات کد بالا میتوان گفت :
۱- برای هر object باید یک شیء temp ایجاد کنیم.
۲- ممکن است بخواهیم که حالات یک object را بر روی هارد ذخیره کنیم. با روش فوق کدها خیلی پیچیدهتر خواهند شد.
۳- نوشتن کد به این سبک برای پروژههای بزرگ، پیچیده و مدیریت آن سختتر میشود.
پیاده سازی memento
ما این مثال را در قالب یک پروژه NET Core onsole. ایجاد میکنیم. برای این کار یک پوشهی جدید را ایجاد و درون ترمینال دستور زیر را وارد کنید:
dotnet new console
روشهای زیادی برای پیاده سازی memento وجود دارند. برای پیاده سازی memento ابتدا یک abstract class را به شکل زیر ایجاد میکنیم:
abstract class MementoBase { protected Guid mementoKey = Guid.NewGuid(); abstract public void SaveMemento(Memento memento); abstract public void RestoreMemento(Memento memento); }
اگر به کلاس بالا دقت کنید، این کلاس قرار است parent کلاسهای دیگری باشد که داری دو متد SaveMemento و RestoreMemento برای ذخیره و بازیابی و همچنین یک Guid برای نگهداری stateهای مختلف میباشد.
ورودی متدها از نوع memento میباشد. پس کلاس memento را به شکل زیر ایجاد میکنیم:
class Memento { private Dictionary<Guid, object> stateList = new Dictionary<Guid, object>(); public object GetState(Guid key) { return stateList[key]; } public void SetState(Guid key, object newState) { stateList[key] = newState; } public Memento() { } }
در کد بالا با یک Dictionary میتوان هر object را با کلیدش ذخیره کنیم. توجه کنید که value دیکشنری از نوع object میباشد و چون object پدر تمام objectهای دیگر است پس میتوانیم هر نوع دادهای را در آن ذخیره کنیم. تا اینجا، Memento پیاده سازی شده است. میتوان این کار را با جنریکها نیز پیاده سازی کرد.
در ادامه میخواهیم یک کلاس بسازیم و حالتهای مختلف را در آن بررسی کنیم. کلاس زیر را ایجاد کنید:
class ConcreteOriginator : MementoBase { private int value = 0; public ConcreteOriginator(int newValue) { SetData(newValue); } public void SetData(int newValue) { value = newValue; } public void Speak() { Console.WriteLine("My value is " + value.ToString()); } public override void SaveMemento(Memento memento) { memento.SetState(mementoKey, value); } public override void RestoreMemento(Memento memento) { int restoredValue = (int)memento.GetState(mementoKey); SetData(restoredValue); } }
کلاس ConcreteOriginator از کلاس MementoBase ارث بری کرده و دو متد RestoreMemento و SaveMemento را پیاده سازی میکند و همچنین دارای یک مشخصه value میباشد. برای خروجی گرفتن، متد main را به صورت زیر پیاده سازی میکنیم:
static void Main(string[] args) { Memento memento = new Memento(); // Create an originator, which will hold our state data. ConcreteOriginator myOriginator = new ConcreteOriginator("Hello World!", StateType.ONE); ConcreteOriginator anotherOriginator = new ConcreteOriginator("Hola!", StateType.ONE); ConcreteOriginator2 thirdOriginator = new ConcreteOriginator2(7); // Set some state data. myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); // Save the states into our memento. myOriginator.SaveMemento(memento); anotherOriginator.SaveMemento(memento); thirdOriginator.SaveMemento(memento); // Now change our originators' states. myOriginator.SetData("Goodbye!", StateType.TWO); anotherOriginator.SetData("Adios!", StateType.TWO); thirdOriginator.SetData(99); myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); // Restore our originator's state. myOriginator.RestoreMemento(memento); anotherOriginator.RestoreMemento(memento); thirdOriginator.RestoreMemento(memento); myOriginator.Speak(); anotherOriginator.Speak(); thirdOriginator.Speak(); Console.ReadKey(); }
Hello World! I'm in state ONE Hola! I'm in state ONE My value is 7 Goodbye! I'm in state TWO Adios! I'm in state TWO My value is 99 Hello World! I'm in state ONE Hola! I'm in state ONE My value is 7
تصمیم گرفتم در طی چندین پست در حد توانم به آموزش jQuery بپردازم. (مطالب نوشته شده برداشت ازادی از کتاب jQuery in action است)
جی کوئری (jQuery) چیست؟
نکته: برای استفاده از جی کوئری باید HTML و CSS و جاوا اسکریپت آشنایی داشته باشید.
چگونه از جی کوئری استفاده کنیم؟
برای استفاده از جی کوئری باید ابتدا فایل آن را از سایت آن دانلود کرده و در پروژه خود استفاده نمایید. البته روشهای دیگری برای استفاده از این فایل وجود دارد که در آینده بیشتر با آن آشنا خواهیم شد. برای استفاده از این فایل در پروژه باید به شکل زیر آن را به صفحه HTML خود معرفی کنیم.
<html> <head> <script type="text/javascript" src="jquery-1.9.1.min.js"></script> </head> <body> </body> </html>
کوتاه کردن کد: هر زمان شما خواسته باشید کارکرد یک صفحه وب را پویاتر کنید، در اکثر مواقع به ناچار این کار از طریق عناصری بروی صفحه انجام داده اید که با توجه به انتخاب شدن آنها، صفحه کارکردی خاص خواهد داشت. مثلا در جاوا اسکریپت اگر بخواهیم عنصری را که در یک radioGroup انتخاب شده است را برگردانیم باید کدهای زیر را بنویسیم:
var checkedValue; var elements = document.getElementByTagName ('input'); for (var n = 0; n < elements.length; n++) { if (elements[n].type == 'radio' && elements[n].name == 'myRadioGroup' && elements[n].checked) { checkedValue = elements[n].value; } }
var checkedValue = $ ('[name="myRadioGroup"]:checked').val();
قدرت اصلی جی کوئری برگفته از انتخابکنندهها (Selector) هاست، انتخابکننده ، یک عبارت است که دسترسی به عنصری خاص بر روی صفحه را موجب میشود؛ انتخابکننده این امکان را فراهم میسازد تا به سادگی عنصر مورد نظر را مشخص و به آن دسترسی پیدا کنیم که در مثال فوق، عنصر مورد نظر ما گزینه انتخاب شده از myRadioGroup بود.
Unobtrusive JavaScript: اگر پیش از پیدایش CSS در کار ایجاد صفحههای اینترنتی بودهاید حتما مشکلات و مشقات آن دوران را به خاطر میآورید. در آن زمان برای فرمتدهی به اجزای مختلف صفحه ، به ناچار علائم فرمتدهی را به همراه دستورات خود اجزا، در صفحههای HTML استفاده میکردیم. اکنون بسیار بعید به نظر میرسد کسی ترجیح دهد فرمتدهی اجزا را به همراه دستورهای HTML آن انجام دهد. اگر چه هنوز دستوری مانند زیر بسیار عادی به نظر میآید:
<button type="button" onclick="document.getElementById('xyz').style.color='red';"> Click Me </button>
مجموعه عناصر در جی کوئری:
زمانی که CSS به عنوان یک تکنولوژی به منظور جداسازی طراحی از ساختار به دنیای صفحههای اینترنتی معرفی شد، میبایست راهی برای اشاره به اجزای صفحات از طرف فایل CSS نیز معرفی میشد. این امر از طریق انتخابکنندهها (Selector) صورت پذیرفت.
برای مثال انتخابکننده زیر، به تمام عناصر <a> اشاره دارد که در یک عنصر <p> قرار گرفتهاند:
p a
برای انتخاب مجموعهای از عناصر از یکی از دو Syntax زیر استفاده میکنیم.
$(Selector) یا jQuery(Selector)
مثال زیر نمونهای دیگر است که در آن مجموعهای از تمام لینکهایی که درون تگ <p> قرار دارند را انتخاب میکند:
$("p a")
در اصطلاح برنامه نویسی به چنین توابعی که گروهی از عناصر را جمع میکنند، Wrapper میگویند زیرا تمام عناصر مطلوب را تحت یک شی بستهبندی میکند. در جیکوئری به آنها Wrapped Set یا jQuery Wrapper میگویند و به متدهایی که قابل اعمال بروی اینها به نام jQuery Wrapper Methodes شناخته میشوند.
در مثال زیر میخواهیم تمام عناصر <div> در صورتی که دارای کلاس notLongForThisWorldباشند را مخفی (با فید شدن) کنیم.
$("div.notLongForThisWorld").fadeOut();
فرض کنید در مثال بالا بخواهیم پس از مخفی کردن هر <div> بخواهیم یک کلاس به نام removedبه آن بیافزاییم. به این منظور میتوان کدی مانند زیر نوشت:
$("div.notLongForThisWorld").fadeOut().addClass("removed");
چند نمونه انتخاب کننده:
نتیجه | انتخاب کننده | |
تمام <p>های زوج را انتخاب میکند | $('p:even') | |
سطر اول هر جدول را انتخاب میکند | $("tr:nth-child(1)"); | |
<div>هایی که مستقیما در <body> تعریف شده باشند را انتخاب میکند. | $("body > div"); | |
لینک هایی که به یک فایل pdf اشاره دارند را انتخاب میکند. | $("a[href$=pdf]"); | |
تمام <div> هایی که مستقیما در <body> معرفی شده اند و دارای لینک میباشند را انتخاب میکند. | $("body > div:has(a)") | |
ادامه مطالب در پستهای بعدی تشریح خواهد شد.
جهت مطالعه بیشتر میتوانید از این منابع ^ و ^ و ^ و ^ و ^ استفاده کنید.
موفق و موید باشید
// The getDate() function returns a nested function which refers the 'date' variable defined // by outer function getDate() function getDate() { var date = new Date(); // This variable stays around even after function returns // nested function return function () { return date.getMilliseconds(); } }
// Once getDate() is executed the variable date should be out of scope and it is, but since // the inner function // referenes date, this value is available to the inner function. var dt = getDate(); alert(dt()); alert(dt());
function myNonClosure() { var date = new Date(); return date.getMilliseconds(); }
var MyDate = function () { var date = new Date(); var getMilliSeconds = function () { return date.getMilliseconds(); } } var dt = new MyDate(); alert(dt.getMilliSeconds()); // This will throw error as getMilliSeconds is not accessible.
// This is closure var MyDate = function () { var date = new Date(); // variable stays around even after function returns var getMilliSeconds = function () { return date.getMilliseconds(); }; return { getMs : getMilliSeconds } }
var dt = new MyDate(); alert(dt.getMs()); // This should work.
(function($) { // $() is available here })(jQuery);
// file1.js function saveState(obj) { // write code here to saveState of some object alert('file1 saveState'); } // file2.js (remote team or some third party scripts) function saveState(obj, obj2) { // further code... alert('file2 saveState"); }
<script src="file1.js" type="text/javascript"></script> <script src="file2.js" type="text/javascript"></script>
function App() { var save = function (o) { // write code to save state here.. // you have acces to 'o' here... alert(o); }; return { saveState: save }; }
var app = new App(); app.saveState({ name: "rajesh"});
Rider 2019.2 منتشر شد
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>(); });