none
How Can I achieve this ? RRS feed

  • Question

  • Hi All,

    I have the below existing code which I want to re use for my new model class "NewStocks" but the below code is tightly coupled to the class "OldStocks" and both these classes (NewStocks,OldStocks) have very less things in common
    But this below logic is something that will be used in NewStock as well . Could you please suggest me some good approaches to decouple this below logic ?
      private abstract class FieldMapper
            {
                /// <summary>
                /// Gets or sets the name.
                /// </summary>
                public string Name { get; protected set; }

                /// <summary>
                /// Gets or sets the column types.
                /// </summary>
                public Table.ColumnType[] ColumnTypes { get; set; }

                /// <summary>
                /// Gets the copy value to filter delegate.
                /// </summary>
                /// <param name="table">The table.</param>
                /// <returns>The delegate.</returns>
                public abstract CopyValueToFilterDelegate GetCopyValueToFilterDelegate(Table table);

                /// <summary>
                /// Gets the copy value to table delegate.
                /// </summary>
                /// <param name="table">The table.</param>
                /// <returns>The delegate.</returns>
                public abstract CopyValueToTableDelegate GetCopyValueToTableDelegate(Table table);

                /// <summary>
                /// Set filterField to null
                /// </summary>
                /// <param name="filter">The filter to clear the field on.</param>
                public abstract void ClearFilterField(OfferFilter filter);
            }

    private abstract class FieldMapper<TData> : FieldMapper
            {
               
                protected Action<OfferFilter, TData> FilterFieldSetter { get; set; }           
                protected Func<OldStocks, TData> OfferFieldGetter { get; set; }
            }

            private class TextFieldMapper : FieldMapper<string>
            {
                
                public TextFieldMapper(string name, Action<OfferFilter, string> filterFieldSetter, Func<OldStocks, string> offerFieldGetter)
                {
                    Name = name;
                    ColumnTypes = new[] { Table.ColumnType.Text };
                    FilterFieldSetter = filterFieldSetter;
                    OfferFieldGetter = offerFieldGetter;
                }
    }
    Wednesday, October 24, 2018 10:10 AM

Answers

  • Hi Rehan Mubarak,

    you can use more generic parameters and make a constraint on an interface type, this way your design will be more decoupled, consider this code for abstractions:

    public interface IFilter<TType, TResult>
        where TType: IDataType<TType>
        where TResult: IResultType<TType>
    {
        Func<TType, TResult> Filter { get; set; }
    }
    
    public interface IDataType<TType> 
    {
    
    }
    
    public interface IResultType<TType> 
    {
        
    }
    
    public abstract class FieldMapper<TDataType, TResultType, TFilter> 
        where TFilter: IFilter<TDataType, TResultType>
        where TDataType: IDataType<TDataType>
        where TResultType: IResultType<TDataType>
    {
        public string Name { get; protected set; }
        public Table.ColumnType[] ColumnTypes { get; set; }
        public abstract CopyValueToFilterDelegate GetCopyValueToFilterDelegate(Table table);
        public abstract CopyValueToTableDelegate GetCopyValueToTableDelegate(Table table);
        public abstract void ClearFilterField(TFilter filter);
    
        protected virtual Action<TFilter, TDataType> FilterFieldSetter { get; set; }
        protected virtual Func<TDataType, TResultType> FieldGetter { get; set; }
    }

    and then the implementation:

    public class OfferField: IDataType<OfferField>
    {
    
    }
    
    public class OfferFilterResult: IResultType<OfferField>
    {
    
    }
    
    public class OfferFilter : IFilter<OfferField, OfferFilterResult>
    {
        public Func<OfferField, OfferFilterResult> Filter { get; set; }
    }
    
    public class OfferFilterFieldMapper : FieldMapper<OfferField, OfferFilterResult, OfferFilter>
    {
        protected override Func<OfferField, OfferFilterResult> FieldGetter { get; set; }
        protected override Action<OfferFilter, OfferField> FilterFieldSetter { get; set; }
        public override void ClearFilterField(OfferFilter filter)
        {
        }
    
        public override CopyValueToFilterDelegate GetCopyValueToFilterDelegate(Table table)
        {
            throw new NotImplementedException();
        }
    
        public override CopyValueToTableDelegate GetCopyValueToTableDelegate(Table table)
        {
            throw new NotImplementedException();
        }
    }

    with this kind of code and some reflection and dictionaries to cache metadata you'll be able to map and use any kind of filtering, this was just an on the fly code to demonstrate the flexibility we can reach using interfaces and generics.

    Good Coding;


    Wednesday, October 24, 2018 7:04 PM

All replies

  • NewStock and OldStock are not names for classes they sound more like property on a StockItem object. Imagine later someone asked about future stock, what you going to do? implement another class?, that will just add complexity to your code base.

    Although you talking about stock but the code you showing are more or less of a helper classes, so its not clear your question.

    General tip, when we have code that we need to maximize its reuse, that's where the interfaces gets in.


    Fouad Roumieh

    Wednesday, October 24, 2018 1:47 PM
  • Hi Rehan Mubarak,

    you can use more generic parameters and make a constraint on an interface type, this way your design will be more decoupled, consider this code for abstractions:

    public interface IFilter<TType, TResult>
        where TType: IDataType<TType>
        where TResult: IResultType<TType>
    {
        Func<TType, TResult> Filter { get; set; }
    }
    
    public interface IDataType<TType> 
    {
    
    }
    
    public interface IResultType<TType> 
    {
        
    }
    
    public abstract class FieldMapper<TDataType, TResultType, TFilter> 
        where TFilter: IFilter<TDataType, TResultType>
        where TDataType: IDataType<TDataType>
        where TResultType: IResultType<TDataType>
    {
        public string Name { get; protected set; }
        public Table.ColumnType[] ColumnTypes { get; set; }
        public abstract CopyValueToFilterDelegate GetCopyValueToFilterDelegate(Table table);
        public abstract CopyValueToTableDelegate GetCopyValueToTableDelegate(Table table);
        public abstract void ClearFilterField(TFilter filter);
    
        protected virtual Action<TFilter, TDataType> FilterFieldSetter { get; set; }
        protected virtual Func<TDataType, TResultType> FieldGetter { get; set; }
    }

    and then the implementation:

    public class OfferField: IDataType<OfferField>
    {
    
    }
    
    public class OfferFilterResult: IResultType<OfferField>
    {
    
    }
    
    public class OfferFilter : IFilter<OfferField, OfferFilterResult>
    {
        public Func<OfferField, OfferFilterResult> Filter { get; set; }
    }
    
    public class OfferFilterFieldMapper : FieldMapper<OfferField, OfferFilterResult, OfferFilter>
    {
        protected override Func<OfferField, OfferFilterResult> FieldGetter { get; set; }
        protected override Action<OfferFilter, OfferField> FilterFieldSetter { get; set; }
        public override void ClearFilterField(OfferFilter filter)
        {
        }
    
        public override CopyValueToFilterDelegate GetCopyValueToFilterDelegate(Table table)
        {
            throw new NotImplementedException();
        }
    
        public override CopyValueToTableDelegate GetCopyValueToTableDelegate(Table table)
        {
            throw new NotImplementedException();
        }
    }

    with this kind of code and some reflection and dictionaries to cache metadata you'll be able to map and use any kind of filtering, this was just an on the fly code to demonstrate the flexibility we can reach using interfaces and generics.

    Good Coding;


    Wednesday, October 24, 2018 7:04 PM