بهترین ادیتور bootstrap
فونتهای نامرئی در طراحی وب
EF Code First #11
ضمن اینکه این لایه میانی رو که عنوان کردید هم در برنامههای وب میتونه استفاده شود و هم ویندوزی.
پروژهی Awesome Bootstrap
ساختار دادهها چیست؟
نوع داده انتزاعی Abstraction Data Type -ADT
- خطی یا Linear: شامل ساختارهایی چون لیست و صف و پشته است: List ,Queue,Stack
- درختی یا Tree-Like: درخت باینری ، درخت متوازن و B-Trees
- Dictionary : شامل یک جفت کلید و مقدار است در جدول هش
- بقیه: گرافها، صف الویت، bags, Multi bags, multi sets
(void Add(object | افزودن المان به آخر لیست |
(void Remove(object | حذف یک المان خاص از لیست |
()void Clear | حذف کلیه المانها |
( bool Contains(object | شامل این داده میشود یا خیر؟ |
( void RemoveAt(int | حذف یک المان بر اساس جایگاه یا اندیسش |
(void Insert(int, object | افزودن یک المان در جایگاهی (اندیس) خاص بر اساس مقدار position |
(int IndexOf(object | اندیس یا جایگاه یک عنصر را بر میگرداند |
[this[int | ایندکسر ، برای دستریس به عنصر در اندیس مورد نظر |
لیستهای ایستا static Lists
public class CustomArrayList<T> { private T[] arr; private int count; public int Count { get { return this.count; } } private const int INITIAL_CAPACITY = 4; public CustomArrayList(int capacity = INITIAL_CAPACITY) { this.arr = new T[capacity]; this.count = 0; }
public void Add(T item) { GrowIfArrIsFull(); this.arr[this.count] = item; this.count++; } public void Insert(int index, T item) { if (index > this.count || index < 0) { throw new IndexOutOfRangeException( "Invalid index: " + index); } GrowIfArrIsFull(); Array.Copy(this.arr, index, this.arr, index + 1, this.count - index); this.arr[index] = item; this.count++; } private void GrowIfArrIsFull() { if (this.count + 1 > this.arr.Length) { T[] extendedArr = new T[this.arr.Length * 2]; Array.Copy(this.arr, extendedArr, this.count); this.arr = extendedArr; } } public void Clear() { this.arr = new T[INITIAL_CAPACITY]; this.count = 0; }
برای پیاده سازی آن به دو کلاس نیاز داریم. کلاس ListNode برای نگهداری هر المان و اطلاعات المان بعدی به کار میرود که از این به بعد به آن Node یا گره میگوییم و دیگری کلاس <DynamicList<T برای نگهداری دنباله ای از گرهها و متدهای پردازشی آن.
public class DynamicList<T> { private class ListNode { public T Element { get; set; } public ListNode NextNode { get; set; } public ListNode(T element) { this.Element = element; NextNode = null; } public ListNode(T element, ListNode prevNode) { this.Element = element; prevNode.NextNode = this; } } private ListNode head; private ListNode tail; private int count; // … }
از آن جا که نیازی نیست کاربر با کلاس ListNode آشنایی داشته باشد و با آن سر و کله بزند، آن را داخل همان کلاس اصلی به صورت خصوصی استفاده میکنیم. این کلاس دو خاصیت دارد؛ یکی برای المان اصلی و دیگر گره بعدی. این کلاس دارای دو سازنده است که اولی تنها برای عنصر اول به کار میرود. چون اولین بار است که یک گره ایجاد میشود، پس باید خاصیت NextNode یعنی گره بعدی در آن Null باشد و سازندهی دوم برای گرههای شماره 2 به بعد به کار میرود که همراه المان داده شده، گره قبلی را هم ارسال میکنیم تا خاصیت NextNode آن را به گره جدیدی که میسازیم مرتبط سازد. سه خاصیت کلاس اصلی به نامهای Count,Tail,Head به ترتیب برای اشاره به اولین گره، آخرین گره و تعداد گرهها، به کار میروند که در ادامه کد آنرا در زیر میبینیم:
public DynamicList() { this.head = null; this.tail = null; this.count = 0; } public void Add(T item) { if (this.head == null) { this.head = new ListNode(item); this.tail = this.head; } else { ListNode newNode = new ListNode(item, this.tail); this.tail = newNode; } this.count++; }
سازنده مقدار دهی پیش فرض را انجام میدهد. در متد Add المان جدیدی باید افزوده شود؛ پس چک میکند این المان ارسالی قرار است اولین گره باشد یا خیر؟ اگر head که به اولین گره اشاره دارد Null باشد، به این معنی است که این اولین گره است. پس اولین سازندهی کلاس ListNode را صدا میزنیم و آن را در متغیر Head قرار میدهیم و چون فقط همین گره را داریم، پس آخرین گره هم شناخته میشود که در tail نیز قرار میگیرد. حال اگر فرض کنیم المان بعدی را به آن بدهیم، اینبار دیگر Head برابر Null نخواهد بود. پس دومین سازندهی ListNode صدا زده میشود که به غیر از المان جدید، باید آخرین گره قبلی هم با آن ارسال شود و گره جدیدی که ایجاد میشود در خاصیت NextNode آن نیز قرار بگیرد و در نهایت گره ایجاد شده به عنوان آخرین گره لیست در متغیر Tail نیز قرار میگیرد. در خط پایانی هم به هر مدلی که المان جدید به لیست اضافه شده باشد متغیر Count به روز میشود.
public T RemoveAt(int index) { if (index >= count || index < 0) { throw new ArgumentOutOfRangeException( "Invalid index: " + index); } int currentIndex = 0; ListNode currentNode = this.head; ListNode prevNode = null; while (currentIndex < index) { prevNode = currentNode; currentNode = currentNode.NextNode; currentIndex++; } RemoveListNode(currentNode, prevNode); return currentNode.Element; } private void RemoveListNode(ListNode node, ListNode prevNode) { count--; if (count == 0) { this.head = null; this.tail = null; } else if (prevNode == null) { this.head = node.NextNode; } else { prevNode.NextNode = node.NextNode; } if (object.ReferenceEquals(this.tail, node)) { this.tail = prevNode; } }
برای حذف یک گره شماره اندیس آن گره را دریافت میکنیم و از Head، گره را بیرون کشیده و با خاصیت nextNode آنقدر به سمت جلو حرکت میکنیم تا متغیر currentIndex یا اندیس داده شده برابر شود و سپس گره دریافتی و گره قبلی آن را به سمت تابع RemoveListNode ارسال میکنیم. کاری که این تابع انجام میدهد این است که مقدار NextNode گره فعلی که قصد حذفش را داریم به خاصیت Next Node گره قبلی انتساب میدهد. پس به این ترتیب پیوند این گره از لیست از دست میرود و گره قبلی به جای اشاره به این گره، به گره بعد از آن اشاره میکند. مابقی کد از قبیل جست و برگردان اندیس یک عنصر و ... را به خودتان وگذار میکنم.
در روشهای بالا ما خودمان 2 عدد ADT را پیاده سازی کردیم و متوجه شدیم برای دخیره دادهها در حافظه روشهای متفاوتی وجود دارند که بیشتر تفاوت آن در مورد استفاده از حافظه و کارآیی این روش هاست.
لیستهای پیوندی دو طرفه Doubly Linked_List
لیستهای پیوندی بالا یک طرفه بودند و اگر ما یک گره را داشتیم و میخواستیم به گره قبلی آن رجوع کنیم، اینکار ممکن نبود و مجبور بودیم برای رسیدن به آن از ابتدای گره حرکت را آغاز کنیم تا به آن برسیم. به همین منظور مبحث لیستهای پیوندی دو طرفه آغاز شد. به این ترتیب هر گره به جز حفظ ارتباط با گره بعدی از طریق خاصیت NextNode، ارتباطش را با گره قبلی از طریق خاصیت PrevNode نیز حفظ میکند.
این مبحث را در اینجا میبندیم و در قسمت بعدی آن را ادامه میدهیم.
using System.Web.Compilation; namespace DbResourceProvider { public class DbResourceProviderFactory : ResourceProviderFactory { #region Overrides of ResourceProviderFactory public override IResourceProvider CreateGlobalResourceProvider(string classKey) { return new GlobalDbResourceProvider(classKey); } public override IResourceProvider CreateLocalResourceProvider(string virtualPath) { return new LocalDbResourceProvider(virtualPath); } #endregion } }
using System.Globalization; using System.Resources; using System.Web.Compilation; namespace DbResourceProvider { public abstract class BaseDbResourceProvider : IResourceProvider { private DbResourceManager _resourceManager; protected abstract DbResourceManager CreateResourceManager(); private void EnsureResourceManager() { if (_resourceManager != null) return; _resourceManager = CreateResourceManager(); } #region Implementation of IResourceProvider public object GetObject(string resourceKey, CultureInfo culture) { EnsureResourceManager(); if (_resourceManager == null) return null; if (culture == null) culture = CultureInfo.CurrentUICulture; return _resourceManager.GetObject(resourceKey, culture); } public virtual IResourceReader ResourceReader { get { return null; } } #endregion } }
using System; using System.Resources; namespace DbResourceProvider { public class GlobalDbResourceProvider : BaseDbResourceProvider { private readonly string _classKey; public GlobalDbResourceProvider(string classKey) { _classKey = classKey; } #region Implementation of BaseDbResourceProvider protected override DbResourceManager CreateResourceManager() { return new DbResourceManager(_classKey); } public override IResourceReader ResourceReader { get { throw new NotSupportedException(); } } #endregion } }
using System.Resources; namespace DbResourceProvider { public class LocalDbResourceProvider : BaseDbResourceProvider { private readonly string _virtualPath; public LocalDbResourceProvider(string virtualPath) { _virtualPath = virtualPath; } #region Implementation of BaseDbResourceProvider protected override DbResourceManager CreateResourceManager() { return new DbResourceManager(_virtualPath); } public override IResourceReader ResourceReader { get { return new DbResourceReader(_virtualPath); } } #endregion } }
using System.Globalization; using DbResourceProvider.Data; namespace DbResourceProvider { public class DbResourceManager { private readonly string _resourceName; public DbResourceManager(string resourceName) { _resourceName = resourceName; } public object GetObject(string resourceKey, CultureInfo culture) { var data = new ResourceData(); return data.GetResource(_resourceName, resourceKey, culture.Name).Value; } } }
using System.Collections; using System.Resources; using System.Security; using DbResourceProvider.Data; namespace DbResourceProvider { public class DbResourceReader : IResourceReader { private readonly string _resourceName; private readonly string _culture; public DbResourceReader(string resourceName, string culture = "") { _resourceName = resourceName; _culture = culture; } #region Implementation of IResourceReader public void Close() { } public IDictionaryEnumerator GetEnumerator() { return new DbResourceEnumerator(new ResourceData().GetResources(_resourceName, _culture)); } #endregion #region Implementation of IEnumerable IEnumerator IEnumerable.GetEnumerator() { return GetEnumerator(); } #endregion #region Implementation of IDisposable public void Dispose() { Close(); } #endregion } }
using System.Collections; using System.Collections.Generic; using DbResourceProvider.Models; namespace DbResourceProvider { public sealed class DbResourceEnumerator : IDictionaryEnumerator { private readonly List<Resource> _resources; private int _dataPosition; public DbResourceEnumerator(List<Resource> resources) { _resources = resources; Reset(); } public DictionaryEntry Entry { get { var resource = _resources[_dataPosition]; return new DictionaryEntry(resource.Key, resource.Value); } } public object Key { get { return Entry.Key; } } public object Value { get { return Entry.Value; } } public object Current { get { return Entry; } } public bool MoveNext() { if (_dataPosition >= _resources.Count - 1) return false; ++_dataPosition; return true; } public void Reset() { _dataPosition = -1; } } }
<system.web> ... <globalization resourceProviderFactoryType=" نام کامل اسمبلی مربوطه ,نام پرووایدر فکتوری به همراه فضای نام آن " /> ... </system.web>
<globalization resourceProviderFactoryType="DbResourceProvider.DbResourceProviderFactory, DbResourceProvider" />
معماری اطلاعات یا 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. در مقالهای دیگر به آنها خواهیم پرداخت.