问题描述:

The class ProductService, below, gets products based on different filters like by date, country, etc., from a database. ProductsService doesn't follow OCP, as adding new filter like getting products by Price requires changing the ProductsService code. How it can be fixed? Any suggestions/comments would be really helpful.

public class ProductsService : IProductsService

{

public FilteredProducts GetProductsByDate(DateTime startDate, DateTime EndDate)

{

//.....

}

public FilteredProducts GetProductsByCountry(string country)

{

//.....

}

public FilteredProducts GetProductsByCity(string city)

{

//.....

}

}

public class FilteredProducts

{

public IEnumerable<Product> Products{set;get;}

public int uniqueProducts { set; get; }

}

public class Product

{

public int ID{set;get;}

public string Name{set;get;}

public decimal Cost{set;get;}

}

网友答案:

Best way is to represent each operation as separate class.

    public interface IProductFilter
    {
        FilteredProducts GetProducts(); 
    }

    public class GetProductsByDate : IProductFilter
    {
        private DateTime _startDate;
        private DateTime _endDate;

        public GetProductsByDate(DateTime startDate, DateTime EndDate)
        {
            _startDate = startDate;
            _endDate = EndDate;
        }

        public FilteredProducts GetProducts()
        {
            // filter
        }
    }

You can then pass this implementation into your service, where it gets executed.

    public class ProductsService : IProductsService
    {
        public FilteredProducts FilterProducts(IProductFilter filter)
        {
            // execute the filter
            // return the products
        }
    }

You could even go as far as turning it into generic Command (for example here) and executing all your database logic through it, ditching the "service" anti-pattern.

网友答案:

I would have an Interface Called IFilter,which is responsible for FilterConstraints Contract.

public interface IFilter
    {
        void FilterConstraints(String FilterConstraints);
    }

Then i would have classes which are responsible for filtering and have those classes implement the IFilter Inetrface.

 public class FilterByCountry : IFilter
{
     public void FilterConstraints(string FilterConstraints)
     {
       //**Your Filter Constraints**/
     }
}

 public class FilterByCity : IFilter
{
     public void FilterConstraints(string FilterConstraints)
     {
         /**Your Filter Constraints **/
     }
}

This is the main class which has a constructor,that initializes IFilter(This is common among various FilterClassed)

public class ProductService
{
    private IFilter _filter=null;

    public ProductService( IFilter Filter)
    {
        _filter = Filter;
    }


    public void FilterProducts(String Constraints)
    {
         _filter.FilterConstraints(Constraints);
    }
}

So now if you want to call Filterbased on FilterByCountry,it would be like

var filterbycountry=new FilterByCountry();
var Filter=new ProductService(filterbycountry);
filter.FilterProducts("your constraints");

The Catch is if you want to add one more filter,you got have a new class and implement the IFilter to that filter class and have it invoked from product.That is your extending but not modifying the class,preserving open and closed principle

网友答案:

Here the requirement is to add algorithm for each new filter without changing the service class. Strategy pattern fits to this requirement. Hope this is helpful.

相关阅读:
Top