I need some advice on modeling the following movies domain. I have a person entity. This person can be an Actor, Director, Producer and Writer and will often be all. I don't want to dup data in each entity so feel it best to create an abstract base class called Person that each of the Director, Actor and Writer classes inherit from. This has started to smell a when I look at the following test:
[Test] public void Can_Do_It()
{
var actor = new Actor("Clint Eastwood");
var director = //?? Can new it up as he already exists as actor }
Is it more preferable to have a Person Class and then have Classes like Writer that take in an instance of person i.e.
public class Writer(Person person,
string attribute1, string attrribute2)
{...}
A common solution would be to introduce the concept of 'role' (quite fitting in this case). A person can be an Actor in 0+ movies, and/or fill a Director Role.
That also allows you to add attributes to the role, like character-name, dates etc
Edit:
The Role class would have 2-way associations with both Person and Movie.
class Role
{
public Person Contributor { ... }
public Movie Feature { ... }
public RoleType Activity { ... }
}
class Person
{
public List<Role> Contributions { ... }
}
class Movie
{
public List<Role> Contributors { ... }
...
}
You could have a concrete class Person with all the common details of a person, and then the person class would also have a collection/list of roles. The roles would be Actor, Writer, etc. and they would have all the necessary extra attributes + behaviour.
You should look at a composition rather than inheritance based model for this. Fairly standard design pattern for this sort of thing - in fact, I suspect (don't have a copy to hand) that it's in the Gang of Four design patterns book if you want more information.
If your "roles" are finite and can be defined up-front (as seems the case in your example), you could use a bitwise enum flag on the Person class.
class Person {
[Flags]
public enum EnumRole {
None = 0,
Actor,
Director,
Producer,
Writer
}
public Person( EnumRole role ) {
Role = role;
}
public EnumRole Role { get; set; }
public bool CanDo( EnumRole role ) {
return (Role & role) != EnumRole.None;
}
}
Then create your person with the required roles:
Person p = new Person(Person.EnumRole.Actor | Person.EnumRole.Director);
... and check if they have a required role ...
bool canDoIt = p.CanDo(Person.EnumRole.Actor);
Related
Say I have a class Book:
public class Book{
public string Title {get; set;}
}
I want every book to have a Read function that returns a string and accepts a page number - but the internals will be different for every book (poor example, I know). How do I define the signature of a function that must be implemented by instances of this class?
Something like this:
public class Book{ // need to make this abstract?
public string Title {get; set;}
public abstract string Read(int pageNum);
}
// I want to define instances that define their own behavior...
public static Book It => new Book(){ // can't create instance of abstract...
Title = "It",
Read... // what do I do here?
}
My main concerns are:
Keeping things as simple as possible. Implementing interfaces under abstract classes works, but it gives me n*2 things to worry about as I add more instances.
I will need to add a large number of these custom functions - passing Funcs through constructors seems unwieldy.
In practice - this is used to define a Tenant. The Tenants are defined in-memory, and have many static properties like domain, name, adminEmail, etc. Those are tenant-specific properties... but now I am trying to implement tenant-specific behaviors - like GetBooks or FilterUsers. I would like to keep implementation as simple as humanly possible. Right now I have "If TenantA, do this, else if tenantB, do this..." sprinkled throughout my code. I'm trying to consolidate all tenant-specific logic and detail in one place - on instances of the Tenant class.
Further examples of Tenant specific behavior - you have a SaaS forum software. On the homepage of Forum A, you GetCoverPhoto by reading from a static file. On the homepage of Forum B, you GetCoverPhoto by reading from a blog homepage. Currently, I say "If Forum A, do this, else If Forum B, do this". This is the type of tenant-specific behavior that I want to define on the Tenant object, instead of in code. I don't want any tenant-specific code in my core logic.
Is there a simple feature/pattern in the C# language that will achieve this?
What NineBerry said is very valid.
There is one other way of accomplishing what you might want. If you want to dynamicly inject the read method implementation into a Book. This can be seen as strategy pattern. And can be done as interfaces like in many languages, but in simplest form in C# it can be done by delegates. Example:
public class Book{
Func<int, string> readFunc;
public Book(Func<int, string> readFunc)
{
this.readFunc = readFunc;
}
public string Title {get; set;}
public string Read(int pageNum) { return readFunc(pageNum); }
}
Then use it as:
public static Book It => new Book(){
Title = "It",
Read = (pageNum) => ... // Do actual reading in delegate
}
EDIT: With more detail on requirements (but still not everything is obvious) I would do something like this:
public class Tenant
{
// core things go here
public Extensions Extensions { get; }
}
public class Extensions : IEnumerable<IExtension>
{
private IList<IExtension> list = new List<IExtension();
private Tenant { get; set; }
public Extensions(Tenant tenant)
{
Tenant = tenant;
}
public void Add(IExtension extension)
{
extension.Tenant = Tenant;
list.Add(extension);
}
}
public interface IExtension
{
Tenant { get; set; }
// shared interface of extensions if any can be abstracted
}
public interface ICoverPhotoExtension : IExtension
{
Photo GetCoverPhoto();
}
public class FileCoverPhotoExtension : ICoverPhotoExtension
{
public Tenant { get; set; }
Photo GetCoverPhoto() { } // gets photo from file
}
public class BlogCoverPhotoExtension : ICoverPhotoExtension
{
public Tenant { get; set; }
Photo GetCoverPhoto() { } // gets photo from blog
}
usage:
Tenant tenant; // initialized somehow
var coverPhotoExtension = tenant.Extensions.FirstOrDefault<ICoverPhotoExtension>();
Photo photo = coverPhotoExtension?.GetCoverPhoto();
public Interface IBook{
string Title {get; set;}
func<int,string> ReadPage
}
Use containment over inheritance. In the interface example above there is a function in every book that implements IBook that will return a string for that page.
public class MyBook : IBook{
public Title : {get;set;} = "MyBook";
public func<int,string> ReadPage =(pagenumber)=>{
return GetText(pagenumber);
}
public string GetText(int pageNumber){
//read the page text by number here.
}
}
I would make GetText an extension method similar to this, so each book doesn't need to implement GetText itself.
public static class XBook{
public static string GetText(this IBook book, int pageNumber){
///do the work here and returng string
}
}
To use the Extension method concept:
using XBook;
public class MyBook : IBook{
public Title : {get;set;} = "MyBook";
public func<int,string> ReadPage =(pagenumber)=>{
return this.GetText(pagenumber);
}
}
There are more ways to do this... for now, give it a try.
Having different instances of a class implement functions differently is not possible. Instead, you inherit a new class where you implement the separate behaviour.
public abstract class Book
{
public string Title {get; set;}
public abstract string Read(int pageNum);
}
public class ITBook : Book
{
public override string Read(int pageNum)
{
// Code here
}
}
Then use the class like this:
public static Book It => new ITBook()
{
Title = "It",
}
You could use a property of a delegate type in the Book class to use different functions in different instances of the Book class, but these functions would not have access to the other properties and methods of the instance they would be used by.
I am trying to build a class that interacts with the database in my asp.net web application. I need your opinion on how to design it, here's an example of what I have in mind
public class Person
{
int personId;
string name;
string lastName;
public int PersonId
{
get { return personId; }
}
public string Name
{
get { return name; }
set { name = value; }
}
public string LastName
{
get { return lastName; }
set { lastName = value; }
}
public Person()
{
}
public static void Save(Person p)
{
//datalayer here
//save the person class
}
public static Person GetPerson(int person_id)
{
//datalayer here
//get the person from database and return a person class
Person p = new Person();
p.personId = 10;
p.name = "Alex";
return p;
}
}
So that i can use the database methods without having to instantiate the class:
Person p = Person.GetPerson(19);
p.Name = "Alex...";
Person.Save(p);
I appreciate your help.
Use Automatic proerties because your private fields does the same in your code.
I think, Save is an Operation which can be done on an object of Person Entity. So i wont keep it as a Static method. I would move your Save code as a method of the Person object. So that i will call it like obj.Save(). To load the data, I would use an overloaded version of my class constructor.
public class Person
{
int personId;
public int PersonId
{
get { return personId; }
}
public string Name { set;get;}
public string LastName { set;get;}
public Person() {}
public Person(int person_id)
{
//call to datalayer here
//get the person from database and return a person class
personId = 10;
Name= "Alex"; // set the public property value here
}
public bool Save()
{
//datalayer here
//save the person class and return
// true/false /or new ID (change return type)
}
}
And when calling,
Person p = new Person(19); //get existing person
p.Name = "New Name";
p.Save();
EDIT : Another (better) approach is to keep your entity classes as simple POCO's. that means no data acccess / BL code there. It will simply look like
public class Person
{
public int ID { set;get;}
public string Name { set;get;}
}
And have a Repository which does the data operations for you. So your repository may have methods like this
public interface IRepository
{
Person GetPerson(int id);
bool SavePerson(Person person);
}
You may implement this Interface in a class to do your Data Access operations
public class Repository:IRepository
{
//implementation of your DA methods here
}
Now you may call it from different layer(business layer) like this
IRepository repo = new Repository();
var person=repo.GetPerson(19);
person.Name="Updated Name";
repo.Save(person);
I like the persistance ignorance thing: What are the benefits of Persistence Ignorance?)
In that case you should move the Save method to another class so the entity doesnt contain any information how it should be persisted.
What you're after is the factory method pattern for the objects, and the repository pattern for the data access code. I can't explain it nearly as well as the articles, so instead I'll go over the basic ideas and provide some examples.
The goal is to divide up your code base in to layers that deal with one specific type of concern, such as communicating with the user (UI), holding and validating data within the application (business classes / model), or managing data persistence (data access). Keeping these areas neatly divided makes it easier to maintain and debug code or develop in parallel. There are other benefits as well, such as facilitating architecture across multiple physical machines, but that's outside the scope of the question.
The basic structure:
Fetching conceptual progression:
UI -> Person Factory -> Person class -> Repository -> Database
Saving conceptual progression:
UI -> Person class -> Repository -> Database
Person class structure, with explanatory comments inside:
public class Person
{
// various properties & methods
// Constructor access is restricted to control how the class gets consumed.
// All instance management must go through the factories.
protected Person() { /* stuff */ }
// Person factory implementation. It's done inside the Person class so that
// tight control can be kept over constructor access.
// The factory is what gives you your instances of Person.
// It has defined inputs and outputs, as well as more descriptive
// names than constructor overloads, so consumers know what to expect.
// It's also a place to put scaffolding code, so you can avoid doing
// things like setting properties every time you fetch an instance.
// The factory takes care of all the object initialization and returns
// an instance that's ready for use.
public static Person GetPerson(int id)
{
Person p = new Person();
// here you call the repository. It should return either a native
// data structure like DataReader or DataTable, or a simple DTO class
// which is then used to populate the properties of Person.
// the reason for this is to avoid a circular dependency between
// the repository and Person classes, which will be a compile time error
// if they're defined in separate libraries
using(PersonRepository repo = new PersonRepository())
{
DataReader dr = repo.GetPerson(id);
p.FillFromDataReader(dr);
}
return p;
}
protected void FillFromDataReader(DataReader dr)
{ /* populate properties in here */ }
// Save should be an instance method, because you need an instance of person
// in order to save. You don't call the dealership to drive your car,
// only when you're getting a new one, so the factory doesn't do the saving.
public void Save()
{
// Again, we call the repository here. You can pass a DTO class, or
// simply pass the necessary properties as parameters
using(PersonRepository repo = new PersonRepository())
{
this.Id = repo.SavePerson(name, address);
}
}
}
Now, the repository code:
// This class implements IDisposable for easy control over DB connection resources.
// You could also design and implement an IRepository interface depending on your needs.
public class PersonRepository : IDisposable
{
private SqlConnection conn;
public PersonRepository()
{
// in here you initialize connection resources
conn = new SqlConnection("someConnectionString");
}
public void IDisposable.Dispose()
{
// clean up the connection
conn.Dispose();
}
// The instance methods talk to the database
public int SavePerson(string name, string address)
{
// call your stored procedure (or whatever) and return the new ID
using(SqlCommand cmd = conn.CreateCommand())
{
// stuff
return (int)cmd.Parameters["myOutputIDParameter"].Value;
}
}
public DataReader GetPerson(int id)
{
// call your stored procedure (or whatever) and return the fetched data
using(SqlCommand cmd = conn.CreateCommand())
{
// stuff
return cmd.ExecuteReader();
}
}
}
Finally, here's what you'd do at the UI level:
Person joe = Person.GetPerson(joeId);
// stuff
joe.Save();
You are doing right but you can also use automatic properties for you class. It may save some of your time.
eg.
public class Person
{
public int PersonId { get; set;}
public string Name { get; set;}
public string LastName { get; set;}
public Person()
{
}
}
I am trying to think of a good way to model the company objects in a new project. A company on it's on already has a lot of data: office address(es), telephone numbers, email addresses, employees (which also have multiple roles: project member, sales representative, etc) and you name it. Now, when it comes to relationships, a company can do business with another company. Often a company buys or sells to another company. But it can also be a two-way situation in which both companies buy and sell from and to eachother. I want to model these relationships in a model which can handle these situations. Besides that, I have a need to be able to add companies to my administration which I haven't done any business with yet, just a relationship. I don't want to fill in all the debtor details yet, or give them a debtor number. Before the become a debtor, the will become a lead first. I don't want lose classes, because I don't want to replicate all the data. Personel and Contactinformation for instance does not change if I start selling or buying from another company.
My question is: how can I model company so they can have multiple roles?
Some pseudo code or class diagram would be nice!
Thanks in advance for trying to help me on my way.
Regards, Ted
There are many ways to skin this particular cat and making a recommendation really requires access to the requirements of your system in detail plus enough time to consider the options. However, assuming that these relationships cannot be derived (see last paragraph), I would, perhaps, consider something like the following:-
public class Company
{
public string Name { get; set; }
public IEnumerable<Relationship>
{
get { ... }
}
}
public class Relationship
{
public RelationshipType { get; set; }
public Company { get; set; }
}
public enum RelationshipType
{
Other,
Debtor,
Creditor,
Lead,
}
This is assuming that the differences between the relationships are trivial as far as your OO model is concerned. If, however, you require behaviors from your relationships specific to the type, then I would consider subtyping, e.g.:-
public class Relationship
{
public Company { get; set; }
public virtual void Foo()
{
....
}
}
public class Debtor : Relationship
{
public override void Foo()
{
....
}
}
public class Creditor : Relationship
{
public override void Foo()
{
....
}
}
public class Lead : Relationship
{
public override void Foo()
{
....
}
}
Another thing to consider is that these relationships are, ultimately, derivations of interactions between the companies. E.g. a company X is a debtor of company Y if and only if company X owes money to company Y. Is this information contained in your system? If so, do you really want to de-normalize that information or would it be better to derive this on the fly? If this information is external to your system and your system is designed specifically to hold a de-normalization of these facts then you can ignore this paragraph.
I think you are looking for the Accountability and Party concepts. Parties can be companies, but also employees. Two parties can be linked by an accountability. This accountability describes the kind of relationship between the parties. Using these concepts, you can model multiple links of different types between parties of different types.
This actually is an analysis pattern described by Fowler in this article on accountability.
Using Decorators as indicated before would allow you to "transform" a type of relationship into a different one (as well as keep the referential identity of the same company in different roles). The only change I would advise is to keep each type of Relationships as their own Collection as in:
public class Company
{
public string Name { get; private set; }
public ISet<Debtor> Debtors { get; private set; }
public ISet<Creditor> Creditors { get; private set; }
public ISet<Lead> Leads { get; private set; }
...
}
public class CompanyRole
{
public Company innerCompany { get; set; }
//Override to allow equality of the same company across Roles
public override bool Equals(object other)
{
if(other is Company)
return ((Company) other).Name.Equals(innerCompany.Name);
else if(other is CompanyRole)
return ((CompanyRole) other).innerCompany.Name.Equals(innerCompany.Name);
else
return false;
}
public override int HashCode()
{
return innerCompany.Name.HashCode();
}
....
}
public class Debtor: CompanyRole
{
....
}
public class Creditor: CompanyRole
{
....
}
public class Lead: CompanyRole
{
....
}
That would allow you to simplify your queries a lot when you are looking for specific types of relationships, without going crazy with too many join-like structures, e.g. '...where myCompany.Debtors.Contains(otherCompany)...'.
I'm working with project that will have ONLY one profile that has friends
I allready do that by
static class profile
class friend
profile has static collection of friends
but profile and friend have same variables as name , pic , .. etc
so i decide to make a person abstract class and inherit it
then i found that i can't inherit static class [ profile ] from person as variables will not have properties
so i made variables as static in person
then every friend doesn't have its variables as static variables will belongs to friend class
I'm new to this and i know it's a silly question !!
but what's the best way to implement this
I Preferred Using Static For Profile For Accessibility
I Preferred Using Static Things For Accessibility Purposes
Avoid using static classes. If you want one instance, just create one instance. Static classes make testing difficult.
But going back to design, maybe try introducing a User class:
class User
- name
- picture
- other properties
class Profile
- User myAccountInfo
- List<User> friends
Maybe something like this?:
class User
{
public User(string name, object picture)
{
Name = name;
Picture = picture;
}
public string Name { get; set; }
public object Picture { get; set; } //Change object to a class that holds Picture information.
}
class Profile : User
{
private static Profile _profile;
public List<User> Friends = new List<User>(); //This List<T> can contain instances of (classes that derive from) User.
public Profile(string name, object picture) : base(name, picture) { }
public static Profile GetProfile()
{
return _profile ?? (_profile = new Profile("NameOfProfileHere", null));
}
}
I have the following classes
public class Person
{
public virtual int Id { get; set; }
}
public class Employee : Person
{
public virtual int EmployeeProperty { get; set; }
}
public class Customer : Person
{
public virtual int CustomerProperty { get; set; }
}
Conceptually a the same Person can be both an Employee and a Customer. Also a Person can exist without either an Employee or Customer record. Using Table Per Subclass how can I get this to work.
As it stands now I don't see a way to get NHibernate to work this way. If I create a Person, and then try to create an Employee using an existing Person Id, NHibernate still tries to insert into Person. Is there a way to get NHibernate to realize that I already have a Person and just want to add the Employee record?
I would prefer to not go to Table Per Class or Table Per Hierarchy if possible.
You model is not correct. If a Person can be both a Customer and an Employee, then you should not use inheritance (An Employee is-a Person), but composition (An Employee has-a [corresponding] Person or A Person has-a Employee [role])
This doesn't work in practice in OO. You would probably want to follow a route that says a person has the roles of being a Customer and also has the role of being an Employee.
Here is a simple example of why this can't work in general OO terms.
Person a = new Employee();
Customer b = (Customer)a; // exception