শুক্রবার, ১৫ নভেম্বর, ২০১৩

Single Responsibility Principle (SRP)


  • Single responsibility Øviv †evSvq GKwU class/mehtod Gi change Gi Rb¨ GKwU gvÎ reason _vK‡e A_©vr GKwU class Gi GKwU gvÎ responsibility _vK‡e|




Real world comparison


  • Mr. Alex GKwU software firm G team leader wnmv‡e job K‡ib|
  • Spare time G wZwb †jLv‡jwL, newspaper editing K‡ib|
  • Basically Mr. Alex Gi Rxe‡b multiple responsibilities we`¨gvb|
  • hLb work place G †Kvb wKQz Lvivc nq †hgb †Kvb fz‡ji Rb¨ boss Gi frmbv ïb‡Z nq ZLb Ab¨vb¨ mKj Kv‡Ri Performance Lvivc nq †ÿÎwe‡k‡l H mKj Kv‡Ri †KvbwUB m¤úbœ Kiv m¤¢e nq bv|
  • Basically GKwU KvR Lvivc n‡j me¸‡jvB Lvivc nq|

Identify Problem in Programming

  • Avgiv c~‡e©v³ CodewU ‡`wL-
protected void BtnSearch_Click(object sender, EventArgs e)
{
    var sbCriteria = new StringBuilder();
    using (var db = new SolidDemoEntities())
    {
        var query = db.Documents.AsQueryable();
        if (!String.IsNullOrWhiteSpace(TxbAccount.Text))
        {
            query = query.Where(d => d.Account.StartsWith(TxbAccount.Text));
            sbCriteria.AppendFormat("Account starts with '{0}' AND ", TxbAccount.Text);
        }

        if (!String.IsNullOrWhiteSpace(TxbLastName.Text))
        {
            query = query.Where(d => d.LastName.StartsWith(TxbLastName.Text));
            sbCriteria.AppendFormat("Last Name starts with '{0}' AND ", TxbLastName.Text);
        }

        if (!String.IsNullOrWhiteSpace(TxbFirstName.Text))
        {
            query = query.Where(d => d.FirstName.StartsWith(TxbFirstName.Text));
            sbCriteria.AppendFormat("First Name starts with '{0}' AND ", TxbFirstName.Text);
        }

        if (sbCriteria.Length > 5)
            sbCriteria.Remove(sbCriteria.Length - 5, 5);
        else
            sbCriteria.Append("-- all records --");

        LblCriteria.Text = sbCriteria.ToString();

        LvwResults.DataSource = query.ToArray();
        LvwResults.DataBind();
    }
}
  • Our beleaguered Search button does far too many jobs.
  • Avgv‡`i Search button A‡bK¸‡jv KvR GK‡Î m¤úbœ K‡i
  • Bnv Single Responsibility Principle violate K‡i| d‡j wewfbœ RwUjZvi m„wó nq- hv c~‡e© Av‡jvPbv Kiv n‡q‡Q-
  • GLb hw` Avgiv BtnSearch_Click method  †f‡½ GKvwaK method   ˆZix Kwi Z‡e wK GB problem fix n‡e?
  •  DËi n‡jv bv - KviY ïaygvÎ method mg~n Single responsible Ki‡jB n‡e bv Zvi mv‡_ mv‡_ class †K I single responsibility m¤úbœ n‡Z n‡e|
  • GLb cÖkœ n‡jv Avgiv method Gi wK wK separate class G break out Ki‡ev?
  •  G‡ÿ‡Î Builder Pattern  Use K‡i Avgiv SearchCriteria create Ki‡ev|
  •  Avgiv piece by piece object create Ki‡ev|
  • Then piece mg~n add K‡i building process m¤úbœ Ki‡ev|
  • Object ‡K  piece by piece fvM K‡i  piece mg~n add KivB Builder Pattern.
  • Avgiv `ywU class create Ki‡ev: 
    •  SearchCriteriaBuilder I SearchCriteria.
  • cÖwZwU class Gi GKwU K‡i Responsibility _vK‡e- 
    • SearchCriteriaBuilder  Gi Responsibility n‡jv search criteria assembling Kiv|
    • SearchCriteria Gi Responsibility n‡jv  Searching Criteria mg~n represent Ki‡e|
  • cÖwZwU class Gi Rb¨ Avgiv GKwU K‡i interface add Ki‡ev|
  • Interface Øviv builder†K abstracting Gi gva¨‡g (cieZ©x‡Z Av‡iv builders add n‡j) Avgiv Ab¨vb¨ builders Gi substitute wnmv‡e use Ki‡Z cvi‡ev|
 



·         Dc‡iv³ Diagram G defined mKj classes I interfaces generic T.
·         GLv‡b T n‡”Q Avgv‡`i searching object type i.e. ‡h object Gi Dci searching Ki‡ev Dnvi type (present application G Document)
·         SearchCriteriaBuilder lets you add criteria with the AndStartsWith method.
·         SearchCriteriaBuilder class Gi AndStartsWith method wU criteria add Ki‡Z e¨eüZ nq|
·          SearchCriteria's single responsibility is to present the criteria to the world.
·         The criteria may take the form of a "friendly" (comprehensible to a human) string or an Expression suitable for LINQ to Entities.
·         SearchCriteria class

Solution which will not violate SRP

ISearchCriteriaBuilder<T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
///  Search criteria builds search criteria. GLb ïaygvÎ  simple 'AND' Operator Gi search mg~n  support Ki‡e.
/// </summary>
/// <typeparam name="T">T Øviv †h object Search Kiv n‡e Dnvi type †evSvq</typeparam>
public interface ISearchCriteriaBuilder<T>
{
    /// <summary>
    /// AND-in a criterion that the property starts with a value.
    /// </summary>
    /// <param name="friendlyName">A name to display to the user.</param>
    /// <param name="propertyName">The name of the property being queried. It must be a string property.</param>
    /// <param name="value">The property's value must start with this string in order to make a match.</param>
    /// <returns>This object, for a fluent interface.</returns>
    ISearchCriteriaBuilder<T> AndStartsWith(string friendlyName, string propertyName, string value);

    /// <summary>
    /// Get a SearchCriteria object that reflects the criteria added so far.
    /// </summary>
    /// <returns>A SearchCriteria object.</returns>
    ISearchCriteria<T> GetResult();

}

 

SearchCriteriaBuilder<T>

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;

/// <summary>
/// Builds search criteria. For now, only simple 'AND' searches are supported.
/// </summary>
/// <typeparam name="T">The type of object being searched.</typeparam>
public interface ISearchCriteriaBuilder<T>
{
    /// <summary>
    /// AND-in a criterion that the property starts with a value.
    /// </summary>
    /// <param name="friendlyName">A name to display to the user.</param>
    /// <param name="propertyName">The name of the property being queried. It must be a string property.</param>
    /// <param name="value">The property's value must start with this string in order to make a match.</param>
    /// <returns>This object, for a fluent interface.</returns>
    ISearchCriteriaBuilder<T> AndStartsWith(string friendlyName, string propertyName, string value);

    /// <summary>
    /// Get a SearchCriteria object that reflects the criteria added so far.
    /// </summary>
    /// <returns>A SearchCriteria object.</returns>
    ISearchCriteria<T> GetResult();

}

using System;
using System.Collections.Generic;
using System.Linq;
using System.Web;
using System.Linq.Expressions;
/// <summary>
/// Represents the criteria for searching for objects of type T.
/// </summary>
/// <typeparam name="T">The type of objects being searched.</typeparam>
public interface ISearchCriteria<T>
{
    /// <summary>
    /// Get a friendly representation of the criteria.
    /// </summary>
    string FriendlyString { get; }

    /// <summary>
    /// Get the criteria as a LINQ Expression.
    /// </summary>
    Expression<Func<T, bool>> Expression { get; }

}

SearchCriteria<T>

using System;
using System.Diagnostics.Contracts;
using System.Linq.Expressions;

    /// <summary>
    /// Represents criteria for searching a repository of objects of type T.
    /// </summary>
    public class SearchCriteria<T> : ISearchCriteria<T>
    {
        /// <summary>
        /// Get a friendly representation of the criteria.
        /// </summary>
        public string FriendlyString { get; private set; }

        /// <summary>
        /// Get the criteria as a LINQ Expression.
        /// </summary>
        public Expression<Func<T, bool>> Expression { get; private set; }

        /// <summary>
        /// Constructor. It is internal because it is intended that the SearchCriteriaBuilder,
        /// in this assemby, be used to construct SearchCriteria.
        /// </summary>
        /// <param name="friendlyString">A user-friendly way of expressing the search criteria.</param>
        /// <param name="expression">A LINQ Expression that contains the search criteria.</param>
        internal SearchCriteria(string friendlyString, Expression<Func<T, bool>> expression)
        {
            Contract.Requires(friendlyString != null);
            Contract.Requires(expression != null);

            FriendlyString = friendlyString;
            Expression = expression;
        }
    }
 For faithfully adhering to the Single Responsibility Principle, we have been rewarded with a set of classes and interfaces that are eminently reusable and -- just as important -- easily testable. That's the 'S' of SOLID.

Can a single class can have multiple methods?

·         SRP Gi †ÿ‡Î GKwU class G multiple method _vK‡Z cvi‡e-
·         GLb cÖkœ n‡jv
1.       GKwU class Gi single responsibility _vK‡e
2.       GKwU method Gi single responsibility _vK‡e
3.       GKwU class G GKvwaK method _vK‡Z cvi‡e
Bnv wKfv‡e m¤¢e?
·         Responsibility mvavibZ context related nq|
·         Class Gi †ÿ‡Î D³ Class Gi mKj method mg~n GKwU specific context related Operation Gi Rb¨ responsible _vK‡e-
o   D`vniY ¯^iƒc EmployeeDB classwU employee related Database operation mg~‡ni Rb¨ responsible _vK‡e|
o    Avevi EmployeeReport classwU employee reports related  operation mg~‡ni Rb¨ responsible _vK‡e|
·         Method Gi †ÿ‡Î GKwU method GKwU specific task handle Ki‡e-
o   ‡hgb wb‡¤œi method wU multiple task handle K‡i
o   wb‡¤œi method wU †hB mKj task mg~n handle K‡i Zv wb‡¤œ cÖ`Ë n‡jv-
§  Connectionstring ‡_‡K  Connection create K‡i
§  Parameter array Create K‡i
§  Command create K‡i
§  Parameter array ‡K command parameter G add K‡i
o   myZivs wb‡¤œi method wU SRP violate K‡i
o   wb‡¤œ method definition ‡`qv n‡jv-
//Method with multiple responsibilities – violating SRP
public void Insert(Employee e)
{    
    string StrConnectionString = "";      
    SqlConnection objCon = new SqlConnection(StrConnectionString);
    SqlParameter[] SomeParameters=null;//Create Parameter array from values
    SqlCommand objCommand = new SqlCommand("InertQuery", objCon);
    objCommand.Parameters.AddRange(SomeParameters);
    ObjCommand.ExecuteNonQuery();
}

o   Dc‡iv³ Method wU SRP supportable Kivi Rb¨ Avgiv Method wU †f‡½ wewfbœ fv‡M fvM Kwi hvi definition wb¤œiƒc-
//Method with single responsibility – follow SRP
public void Insert(Employee e)
{           
    SqlConnection objCon = GetConnection();
    SqlParameter[] SomeParameters=GetParameters();
    SqlCommand ObjCommand = GetCommand(objCon,"InertQuery",SomeParameters);
    ObjCommand.ExecuteNonQuery();
}

private SqlCommand GetCommand(SqlConnection objCon, string InsertQuery, SqlParameter[] SomeParameters)
{
    SqlCommand objCommand = new SqlCommand(InsertQuery, objCon);
    objCommand.Parameters.AddRange(SomeParameters);
    return objCommand;
}

private SqlParameter[] GetParaeters()
{
    //Create Paramter array from values
}
private SqlConnection GetConnection()
{
    string StrConnectionString = "";
    return new SqlConnection(StrConnectionString);
}
·         GB‡ÿ‡Î Method msL¨ I code quantity  †e‡o †M‡jI
o   Testability ev‡o|
o   Code readable nq|
o   Specific method Gi responsibility reduce nq|

কোন মন্তব্য নেই:

একটি মন্তব্য পোস্ট করুন