Share via


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";
    }
}

See Also