I have this class with these two methods and a list:
public class Example
{
protected List<Person> ExampleList = new List<Person>();
public Example()
{
CreatePersonInstances();
foreach (Person personToInitialize in ExampleList)
personToInitialize.Initialize();
}
protected void CreatePersonInstances()
{
ExampleList.Add(new Employee());
ExampleList.Add(new Manager());
ExampleList.Add(new Recruiter());
}
}
How can I create properly a specific number of items from a user defined quantity?
For example, if the user decides to create two employees, a manager and zero recruiters, I have to be able to create the defined quantity of objects in CreatePersonInstaces();
protected void CreatePersonInstances(int employeeCount, int managerCount, int recruiterCount)
{
//some validation to check count number not negative
ExampleList.AddRange(Enumerable.Range(0, employeeCount).Select(x => new Employee()));
ExampleList.AddRange(Enumerable.Range(0, managerCount).Select(x => new Manager()));
ExampleList.AddRange(Enumerable.Range(0, recruiterCount).Select(x => new Recruiter()));
}
where Employee, Manager and recruiter inherit from Person entity
public class Person
{
public string Name { get; set; }
}
public class Employee : Person
{
public int EmployeeId { get; set; }
}
public class Manager : Person
{
public int ManagerId { get; set; }
}
public class Recruiter : Person
{
public int RecruiterId { get; set; }
}
Besides the scope of the question, this whole model is a good use case for the Factory Design Pattern. If you havent, check it out 👍
You could begin by adding 3 parameters in the constructor, - a parameter each signifying number of Employee/Manager/Recruiter to create.
public Example(int employee,int manager,int Recruiter)
{
// Rest of code
}
You could also make your CreatePersonInstances method generic that accepts a parameter type which inherits from Person along with number of instances to create.
protected void CreatePersonInstances<T>(int count) where T:Person,new()
{
EmployeeList.AddRange(IEnumerable.Range(1,count).Select(x=>new T()));
}
You could now change your constructor definition as
public Example(int employeeCount,int managerCount,int recruiterCount)
{
CreatePersonInstances<Employee>(employeeCount);
CreatePersonInstances<Manager>(managerCount);
CreatePersonInstances<Recruiter>(recruiterCount);
foreach (Person personToInitialize in ExampleList)
personToInitialize.Initialize();
}
Related
Let me describe a simplified story on this. I try to design a recommend function, it will recommend you different product by different match rules.
// TV will match a product by given TV related parameters
public class TvMatcher
{
public Product Match(ITvMatchParam tvMatchParam)
{
return new Product(); // pick a tv by tvMatchParam
}
}
public interface ITvMatchParam
{
int Age { get; }
int Gender { get; }
}
// Phone will match a product by given Phone related parameters
public class PhoneMatcher
{
Product Match(IPhoneMatchParam phoneMatchParam)
{
return new Product(); // pick a phone by phoneMatchParam
}
}
public interface IPhoneMatchParam
{
int Age { get; }
int Education { get; }
}
The Recommend here is a public API which accept a union parameters.
Then it will pick a Matcher and call match() to pick a product.
public class Main
{
public Product Recommend(AllMatchParams allParams)
{
// pseudo code here, can't compile
IMatcher matcher = CreateMatcherFactoryMethod(allParams);
return matcher.Match(allParams);
}
private static IMatcher CreateMatcherFactoryMethod(AllMatchParams allParams)
{
IMatcher matcher;
if (allParams.Product == 0)
{
matcher = new TvMatcher();
}
else
{
matcher = new PhoneMatcher();
}
return matcher;
}
}
class AllMatchParams : ITvMatchParam, IPhoneMatchParam
{
public int Age { get; }
public int Education { get; }
public int Gender { get; }
public int Product { get; }
}
But above code won't be compiled because TvMatcher and PhoneMatcher cannot implement IMatcher
public interface IMatcher
{
Product Match(AllMatchParams allMatchParams);
}
Since TvMatcher only cares Tv related parameters, PhoneMatcher only cares PhoneMatcher related parameters, I don't want to force PhoneMatcher implment IMatcher.
public class PhoneMatcher: IMatcher
{
Product Match(AllMatchParams allParams)
{
// don't like this because PhoneMatcher only cares subset properties in allParams
}
}
So I try to implement an AbstractClass and make PhoneMatcher inherit it. I hope it can accept a AllMatchParams and only see PhoneMatchParam in implementation.
public abstract class AbstractMatcher<TProductMatchParam>: IMatcher
{
public Product Match(AllMatchParams allMatchParams)
{
return ProductMatch(allMatchParams); // fails here
}
protected abstract Product ProductMatch(TProductMatchParam param);
}
public class PhoneMatcher: AbstractMatcher<IPhoneMatchParam>
{
protected Product ProductMatch(IPhoneMatchParam phoneMatchParam)
{
// ...
}
}
public class TvMatcher: AbstractMatcher<ITvMatchParam>
{
protected Product ProductMatch(ITvMatchParam tvMatchParam)
{
// ...
}
}
But above code won't compile because AllMatchParams cannot cast to generic variable <TProductMatchParam>.
Is there a way to make AbstractMatcher.Match can accept a fixed type parameter and delegate to child, so child can see different interfaces of that parameter?
I had tried to add constraints to generic variable but fail because cannot make TProductMatchParam constraint to either IPhoneMatchParam or ITvMatchParam at same time.
Your AbstractMatcher is a bit too much
You could make your IMatcher interface generic instead :
public interface IMatcher<T>
{
Product Match(T matchParam);
}
public class PhoneMatcher: IMatcher<IPhoneMatchParam>
{
public Product Match(IPhoneMatchParam matchParam)
{
// ...
}
}
public class TvMatcher: IMatcher<ITvMatchParam>
{
public Product Match(ITvMatchParam matchParam)
{
// ...
}
}
In this case you can pass your AllMatchParams instance in the 2 methods.
return new PhoneMatcher().Match(criteria) ?? new TvMatcher().Match(criteria);
Will returns the first not null matched product
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 6 years ago.
Improve this question
My Question is when i am having list of objects, should i pass the entire list to a methods in another layer or should i have another model and make the new list of it?
namespace Model
{
Public Class class2
{
blah blah properties
}
Public Class Person
{
public string firstname { get; set; }
public string lastname {get; set;}
public int age {get; set;}
public Datetime regDate {get; set;}
public class2 SomeClass{get; set;}
}
}
Namespace Service
{
Namespace Model
{
public class LogPerson
{
public string firstName {get; set;}
public string lastName {get; set;}
public int age {get; set;}
}
}
public static class Log
{
//Method1
public void Log(List<Person> persons)
{
LogProvider.Log(Persons.Select(p=> new LogPerson{ p.firstName, p.lastname, p.age}).ToList());
}
//Method2
public void Log(List<LogPerson> persons)
{
LogProvider.Log(persons);
}
}
As i showed above, is it good practice to pass the complete list of persons object (Log provider needs only firstname,lastname and age) or using method2 which needs the LogPerson object from the beginning.
I do not need opinions, what i need is,according to separation of concerns, which one is right way ?
If you define an interface which has the properties you require to log, you can have only one model:
// keep in a separate, shared assembly
public interface ILoggablePerson {
string firstName {get; set;}
string lastName {get; set;}
int age {get; set;}
}
then
public void Log(IEnumerable<ILoggablePerson> people)
{
LogProvider.Log(persons);
}
(note using IEnumerable instead of a List: this means the argument can be lazy evaluated [if required] and doesn't tie the method consumer to a particular data structure)
Finally, your Person class just has to add that interface to its declaration:
public class Person : ILoggablePerson
and then you can just pass in Person objects to your logger class:
Log.Log(new Person[] { ... }); // etc.
Edit following comment
Here's an example of how I might go about this: separation of concerns is still provided by interfaces, just using dependency injection, provider and factory patterns... comments inline, hope it helps.
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using Service;
using Model;
using System.Collections.Concurrent;
namespace ConsoleApplication8
{
class Program
{
static void Main(string[] args)
{
var carLogger = Logger.Default(new Model.CarLogEntryProvider()); // generic type inference
// want to log to a file? => Logger.File(#"c:\file path", new Model.CarLogEntryProvider());
var personLogger = Logger.Default(new Model.PersonLogger());
Car c1 = new Car() { Make = "Toyota", Registration = "ABC123" };
Car c2 = new Car() { Make = "Toyota", Registration = "ABX127" };
carLogger.AddEntries(new Car[] { c1, c2 });
Person p1 = new Person() { Age = 21, FirstName = "Tony", LastName = "Baloney" };
Person p2 = new Person() { Age = 31, FirstName = "Mary", LastName = "O'Doherty" };
personLogger.AddEntry(p1);
personLogger.AddEntry(p2);
Console.ReadLine();
}
}
}
// model namespace knows how the model works and can make the decision of how its types are logged
// by implementing ILogEntryProvider as required: can even combine fields, add additional fields (eg timestamp) etc.
namespace Model
{
public class Person
{
public string FirstName { get; set; }
public string LastName { get; set; }
public int Age { get; set; }
}
public class Car
{
public string Make { get; set; }
public string Registration { get; set; }
}
// knows how to log a Car as required by this namespace: another system can implement this differently
class CarLogEntryProvider : ILogEntryProvider<Car>
{
public ILogEntry GetLogEntry(Car car)
{
var result = new BasicLogEntry(); // can use a ThreadSafeLogEntry if application is multi-threaded
result.Values["make"] = car.Make;
result.Values["reg"] = car.Registration;
return result;
}
}
// knows how to log a Car as required by this namespace: another system can implement this differently
class PersonLogger : ILogEntryProvider<Person>
{
public ILogEntry GetLogEntry(Person person)
{
var result = new BasicLogEntry(); // can use a ThreadSafeLogEntry if application is multi-threaded
result.Values["age"] = person.Age.ToString();
result.Values["surname"] = person.LastName;
return result;
}
}
}
// service namespace has no knowledge of the model, it just provides interfaces for the model to provide
namespace Service
{
public interface ILogEntry {
IDictionary<string, string> Values { get; }
}
public interface ILogEntryProvider<T>
{
// can add any other properties here for fields which are always required
ILogEntry GetLogEntry(T itemToLog);
}
public class ThreadSafeLogEntry : ILogEntry
{
public ThreadSafeLogEntry() { Values = new ConcurrentDictionary<string, string>(); }
public IDictionary<string, string> Values
{
get;
set;
}
}
public class BasicLogEntry : ILogEntry
{
public BasicLogEntry() { Values = new Dictionary<string, string>(); }
public IDictionary<string, string> Values
{
get;
set;
}
}
public interface ILogger<T>
{
void AddEntry(T item);
void AddEntries(IEnumerable<T> items);
}
// factory pattern
public static class Logger
{
public static ILogger<T> Default<T>(ILogEntryProvider<T> entryProvider)
{
return new ConsoleLogger<T>(entryProvider);
}
// create other methods here as required, all returning type ILogger<T>
// eg: public static ILogger<T> File(string filePath, ILogEntryProvider<T> entryProvider) { ... }
}
class ConsoleLogger<T> : ILogger<T>
{
private ILogEntryProvider<T> logEntryProvider;
public ConsoleLogger(ILogEntryProvider<T> logEntryProvider) // dependency injection
{
if (logEntryProvider == null)
throw new ArgumentNullException();
this.logEntryProvider = logEntryProvider;
}
void ILogger<T>.AddEntry(T item) // explicit interface implementation: discourage use of this class in a fashion which doesn't treat it as an interface type
{
((ILogger<T>)this).AddEntries(new T[] { item });
}
void ILogger<T>.AddEntries(IEnumerable<T> items) // explicit interface implementation: discourage use of this class in a fashion which doesn't treat it as an interface type
{
var entries = items.Select(item => logEntryProvider.GetLogEntry(item))
.Where(anyEntry => anyEntry != null) // perhaps a different behaviour required here...
.Select(nonNullEntry => nonNullEntry.Values);
foreach(var entry in entries)
{
Console.WriteLine("New Entry: {0}", typeof(T).Name);
foreach(var property in entry.Keys)
{
// record each string pair etc. etc
string propertyValue = entry[property];
Console.WriteLine("[{0}] = \"{1}\"", property, propertyValue);
}
Console.WriteLine();
}
}
// TO DO: create an async pattern method:
// public static Task AddEntryAsync<T>(ILogEntryProvider<T> adapterFunc, IEnumerable<T> items) { .... }
}
}
If you want an answer in regards to separation of concerns, if you don't need the properties in what you are passing to, then creating another model and a new list of it is the way to go.
This would separate the concerns of the layers. Layer 2 is not concerned about the unneeded properties of layer 1.
I'm trying to create a reusable method like this
public static void Order<T> (List<T> filteredList, List<T> fullList)
{
//Getting list of ID from all business entities.
HashSet<long> ids = new HashSet<long>(filteredList.Select(x => x.ID));
//Ordering the list
return fullList.OrderByDescending(x => ids.Contains(x.ID)).ThenBy(x => !ids.Contains(x.ID)).ToList();
}
because I have multiple objects that do the same thing but they are differents collections types. But obviously the problem is on x.ID because ID is a property from the business entity. I mean. Imagine that T is Person and ID is the property. But ID is not recognized from a generic list and I want to do it generic because all my business entities have ID (Person, Employee, etc).
Any help please?
Thanks in advance.
L.I.
You could create an Interface, in this example IBusinessEntity, that states the item must have an ID like this:
public interface IBusinessEntity
{
public int ID { get; set; }
}
So, your Person and Employee classes would then change to:
public class Person : IBusinessEntity
{
public int ID { get; set; }
// ...
}
public class Employee : IBusinessEntity
{
public int ID { get; set; }
// ...
}
and then you would only allow Business Entities (in this example Person and Employee) to be passed in like so:
public static void Order<IBusinessEntity> (List<IBusinessEntity> filteredList, List<IBusinessEntity> fullList)
{
//Getting list of ID from all business entities.
HashSet<long> ids = new HashSet<long>(filteredList.Select(x => x.ID));
//Ordering the list
return fullList.OrderByDescending(x => ids.Contains(x.ID)).ThenBy(x => !ids.Contains(x.ID)).ToList();
}
This of course would also allow you to create Mock IBusinessEntity and Unit Test this method.
Thanks for your quick answer. I'd really appreciate it. Well I saw your code and I think is terrific! I did a little app to test it and it has some changes because an interface does not allow me to define public the property and the type in Order shows me a conflict of type IBusinessEntity so I declared it Order T besides that, it's great. Finally this is the last result.
public interface IEntity
{
int id { get; set; }
}
public class Person: IEntity
{
public int id { get; set; }
}
public class Employee : IEntity
{
public int id { get; set; }
}
public static List<IEntity> Order<T>(List<IEntity> filtered, List<IEntity> full)
{
HashSet<int> ids = new HashSet<int>(filtered.Select(x => x.id));
return full.OrderByDescending(x => ids.Contains(x.id)).ThenBy(x => !ids.Contains(x.id)).ToList();
}
Thank you.
L.I.
I'm new to MVC. I can't figure out how to bind a property that can have different types to radiobuttons, like for example:
public class Job { public string Name { get; set; } }
public class Carpenter : Job { }
public class Unemployed : Job { }
public class Painter : Job { }
public class Person
{
public Person() { this.Job = new Unemployed(); }
public Job Job { get; set; }
}
That is; a person has job of some sort. Now I like to have a view where the user can select a job for a person. I'd like to use radiobuttons to display all avalable job types. I'd also like the persons current job type to be selected as default, and of course I would like the person to have her job type updated on postback. I'm trying to use Razor. How would you do this?
I would have a string model property with an identifier for the job type:
public class EmployeeViewModel
{
public string JobType { get; set; }
}
You can then create a bunch of radiobuttons in your view where the values are all available job types. Then, utilize a factory class:
public static class JobFactory
{
public Job GetJob(string id)
{
switch (id)
{
case "CA":
return new Carpenter();
...
}
}
}
You can then call this in your controller:
public ActionResult MyAction(EmployeeViewModel m)
{
var person = new Person();
person.Job = JobFactory.GetJob(m.JobType);
...
}
You might also benefit from switching out the string ID for an enum and using RadioButtonListFor in your view. There's an answer here that demonstrates this:
https://stackoverflow.com/a/2590001/1043198
Hope this helps.
I have a customer hierarchy like so:
abstract class Customer {
public virtual string Name { get; set; }
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
When I retrieve a Customer, I would like to show on the web form the properties to edit/modify. Currently, I use if statements to find the child customer type and show the specialized properties. Is there a design pattern (visitor?) or better way so I can avoid the "if" statements in presentation layer? How do you do it?
Further information: This is an asp.net website with nHibernate backend. Each customer type has its own user control on the page that I would like to load automatically given the customer type.
Can you use reflection to get the list of properties specific to an subclass (instance)? (Less error-prone.)
If not, create a (virtual) method which returns the special properties. (More error prone!)
For an example of the latter:
abstract class Customer {
public virtual string Name { get; set; }
public virtual IDictionary<string, object> GetProperties()
{
var ret = new Dictionary<string, object>();
ret["Name"] = Name;
return ret;
}
}
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Max spending"] = MaxSpending;
return ret;
}
}
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
public override IDictionary<string, object> GetProperties()
{
var ret = base.GetProperties();
ret["Award"] = Award;
return ret;
}
}
You probably want to create sections (fieldsets?) on your Web page, anyway, so if would come into play there, making this extra coding kinda annoying and useless.
I think a cleaner organization would be to have a parallel hierarchy of display controls or formats. Maybe use something like the Abstract Factory Pattern to create both the instance of Customer and of CustomerForm at the same time. Display the returned CustomerForm instance, which would know about the extra properties and how to display and edit them.
new:
interface CustomerEdit
{
void Display();
}
edit:
abstract class Customer {
protected CustomerEdit customerEdit; // customers have an object which allows for edit
public virtual string Name { get; set; }
public void Display() { customerEdit.Display(); } // allow the CustomerEdit implementor to display the UI elements
}
// Set customerEdit in constructor, tie with "this"
class HighValueCustomer : Customer {
public virtual int MaxSpending { get; set; }
}
// Set customerEdit in constructor, tie with "this"
class SpecialCustomer : Customer {
public virtual string Award { get; set; }
}
usage:
Customer whichCouldItBe = GetSomeCustomer();
whichCouldItBe.Display(); // shows UI depeneding on the concrete type
Have you tried something like this:
public class Customer<T>
where T : Customer<T>
{
private T subClass;
public IDictionary<string, object> GetProperties()
{
return subClass.GetProperties();
}
}
With a subclass of:
public class FinancialCustomer : Customer<FinancialCustomer>
{
}
This is off the top of my head so might not work. I've seen this type of code in CSLA.NET.
Here's the link to the CSLA.NET class called BusinessBase.cs which has a similar definition to what I've given above.