SOLID - Open/Closed Principle in C# - Part 1
Open/Closed Principle states that the class should be open for extension and closed for modification. This is done by having a generic base class and the specified dervied class using inheritance.
Example of the base class is follows. This is the generic class used for querying the SharePoint list.
using System;
using System.Collections.Generic;
using System.Configuration;
using Microsoft.SharePoint.Client;
namespace SharePoint.Services
{
public abstract class ServiceBase<T>
{
private readonly string _siteKey;
private readonly string _listKey;
protected ServiceBase(string siteKey, string listKey)
{
_siteKey = siteKey;
_listKey = listKey;
}
public string SiteUrl
{
get { return ConfigurationManager.AppSettings.Get(_siteKey); }
}
public string ListId
{
get { return ConfigurationManager.AppSettings.Get(_listKey); }
}
internal IList<T> Get<TMapper>(SPListQuery query)
where TMapper : SpListItemMapper<T>, new()
{
using (var context = SharePointContext.Initialize(SiteUrl))
{
var mapper = SpListItemCollectionMapper<TMapper, T>.Instance;
var items = context.LoadItems(query);
return context.Execute(items, mapper.Map);
}
}
internal IList<T> Get<TMapper>(SPListQuery query, Action<ListItemCollection, ClientContext> filterAction)
where TMapper : SpListItemMapper<T>, new()
{
using (var context = SharePointContext.Initialize(SiteUrl))
{
var mapper = SpListItemCollectionMapper<TMapper, T>.Instance;
var items = context.LoadItems(query);
return context.Execute(items, filterAction, mapper.Map);
}
}
}
}
The following are the derived classes which will use the base class functionality and implement there own methods. This class uses the Get method which is highlighted from the base class and has its own method like GetByProduct.
using System.Collections.Generic;
namespace SharePoint.Services
{
public sealed class ManageProcessDocService : ServiceBase<ManageProcessDoc>
{
private ManageProcessDocService()
: base(UrlKey, ListIdKey)
{
}
public static ManageProcessDocService Instance
{
get
{
return new ManageProcessDocService();
}
}
public IList<ManageProcessDoc> GetByProduct(string product)
{
var filter = new ManageProcessDocListQueryFilter(product);
var query = new ManageProcessDocListQuery(ListId, filter);
return Get<ManageProcessDocMapper>(query, query.Filter);
}
private IList<ManageProcessDoc> GetManageProcessDocs(SPListQueryFilter filter)
{
var query = new ManageProcessDocListQuery(ListId, filter);
return Get<ManageProcessDocMapper>(query, query.Filter);
}
public IList<ManageProcessDoc> GetAll()
{
var filter = NullListQueryFilter.Instance;
return GetManageProcessDocs(filter);
}
private const string UrlKey = "SPPSiteUrl";
private const string ListIdKey = "DocumentListId";
}
}
The second derived class is using the base class. This class uses the **Get **method which is highlighted from the base class and has its own method like GetByProduct.
using System.Collections.Generic;
namespace SharePoint.Services
{
internal sealed class ReleaseService : ServiceBase<Release>
{
private ReleaseService()
: base(UrlKey, ListIdKey)
{
}
public static ReleaseService Instance
{
get
{
return new ReleaseService();
}
}
internal IList<Release> GetByProduct(string product)
{
var filter = new ManageProcessDocListQueryFilter(product);
return FetchReleases(filter);
}
internal IList<Release> GetAll()
{
var filter = NullListQueryFilter.Instance;
return FetchReleases(filter);
}
internal IList<Release> GetReleaseDetailsByProductList(List<string> products)
{
var filter = new ReleaseListQueryFilter(products);
return FetchReleases(filter);
}
internal IList<Release> GetReleaseDetailsByReleaseList(List<string> releases)
{
var filter = new ReleaseDetailsListQueryFilter(releases);
return FetchReleases(filter);
}
private IList<Release> FetchReleases(SPListQueryFilter filter)
{
var query = new ReleaseListQuery(ListId, filter);
return Get<ReleaseMapper>(query);
}
private const string UrlKey = "SPPSiteUrl";
private const string ListIdKey = "ReleaseListId";
}
}