Don't be scared of the extensive code. The problem is general. I just provided the code to understand the problem better.
I am trying to find out a standard approach of manipulating tables with many-to-many relationships. And I am almost done. Here Teacher and Course have M:M relationship. I have designed my classes as follows:
Teacher - class:
public class Teacher
{
public int ID{get;set;}
public string TeacherName{get;set;}
private List<Course> _items = null;
public List<Course> Items
{
get
{ if (_items == null) {_items = Course.GetCoursesByTeacherID(_ID);}
return _items;
}
set {_items = value;}
}
public int Save()
{ //...
CourseTeacher.DeleteCoursesByTeacherID(tc, id);
CourseTeacher.SaveCoursesWithTeacherID(tc, id, this.Items);
//...
}
public bool Update()
{ //...
CourseTeacher.DeleteCoursesByTeacherID(tc, this.ID);
CourseTeacher.SaveCoursesWithTeacherID(tc, this.ID, this.Items);
//...
}
public static Teacher Get(int id)
{ //...
item.Items = CourseTeacher.GetCoursesByTeacherID(tc, item.ID);//...
}
public static List<Teacher> Get()
{ //...
items[i].Items = CourseTeacher.GetCoursesByTeacherID(tc, items[i].ID);//...
}
public static List<Teacher> GetTeachersByCourseID(int id)
{ //...
items = CourseTeacher.GetTeachersByCourseID(tc, id);//...
}
public bool Delete()
{ //...
CourseTeacher.DeleteCoursesByTeacherID(tc, this.ID);//...
}
}
Course is absolutely similar to Teacher - class. And the mapping class is as follows:
public class CourseTeacher
{
public int CourseID{get;set;}
public int TeacherID{get;set;}
public static void SaveCoursesWithTeacherID(TransactionContext tc, int teacherID, List<Course> items){}
public static void SaveTeachersWithCourseID(TransactionContext tc, int courseID, List<Teacher> items){}
private void Save(TransactionContext tc){}
public static void DeleteCoursesByTeacherID(TransactionContext tc, int teacherID){}
public static void DeleteTeachersByCourseID(TransactionContext tc, int courseID){}
public static List<Teacher> GetTeachersByCourseID(TransactionContext tc, int courseID){}
public static List<Course> GetCoursesByTeacherID(TransactionContext tc, int teacherID){}
}
Now my problem is, this code is not working?
Teacher professorXyz = Teacher.Get(2);
Course cpp = Course.Get(3);
Course java = Course.Get(2);
professorXyz.Items.Remove(cpp);
professorXyz.Items.Remove(java);
professorXyz.Update();
This is not working because it is not probably finding a match or get accessor is returning readonly List.
How should I refactor my Teacher/Course - class to achieve this?
No exception. No problem with persistence code. Items are not being removed.
why professorXyz.Items.Contains(cpp); is returning false?
What to check for?
This is not a direct answer, but...
Your design is very (very) Relational. That makes persisting to a DB easier but you do not have a proper OO model. Maybe you should consider using DataTables in a DataSet and reap the benefits of the Relation class.
To take a shot:
Teacher professorXyz = Teacher.Get(2);
Course cpp = Course.Get(3);
I suspect that the cpp course is being loaded twice, and that there are 2 instances of that course in memory. A very bad consequence of your design. By default, those 2 instances will not be equal and that is why Remove does not work. You could overload Equals, == and GethashCode but that is not recommended for mutable types.
What you really need is a design where for a given Teacher or Course there never exists more than 1 instance in memory.
Re Comment: A MxM relation in OO looks like:
class Teacher
{
public readonly List<Course> Courses = ...;
}
class Course
{
public readonly List<Teacher> Teachers = ...;
}
This will take a little more work to write to a DB but it solves a lot of other problems.
What are you trying to do? Your sample looks like you want to build a relational database table implemented in C#.
If you want to have an OO representation then get rid of the entire CourseTeacher class. That has absolutely nothing to do with OO.
seems you already solved this problem, but consider following code where I overrode bool Equals; C# couldn't knew how to compare your new cpp instance with another instance in your List<Course>, so we need to tell it by creating a more specialized Equals method:
class Teacher
{
private List<Course> items = new List<Course>();
public int ID { get; set; }
public List<Course> Items { get { return items; } }
}
class Course
{
public int ID { get; set; }
public override int GetHashCode() { return base.GetHashCode(); }
public override bool Equals(object obj) { return Equals(obj as Course); }
public bool Equals(Course another)
{
return another != null && this.ID.Equals(another.ID);
}
}
static void Main(string[] args)
{
Teacher teacher = new Teacher { ID = 2 };
teacher.Items.AddRange(
new Course[] {
new Course{ ID = 2 }, // java
new Course{ ID = 3 } }); // cpp
Course cpp = new Course { ID = 3 }; // previous problem: another instance
teacher.Items.Contains(cpp); // now returns true
teacher.Items.Remove(cpp); // now returns true
}
Henk is correct; your design is very, very relational. For this sort of scenario, though, you're better off focusing on behaviour in your objects, and using an object-relational mapping (ORM) tool to translate between your objects and your database.
ADO.NET's DataTable and DataSet don't really offer object-relational mapping capabilities; because they're so tightly coupled to the underlying database schema, they force you to think in terms of columns, tables and relations, when you really want to be thinking in terms of teachers and courses.
I would seriously recommend looking at Castle ActiveRecord for this scenario. It uses the same approach as your example - static Teacher.Get() to retrieve an instance, myTeacher.Save() to save your changes - but there's a LOT of necessary complexity that your example is missing, and using an ORM framework will allow you to ignore this complexity and focus on your own project's requirements.
Here's an example of many-many associations from the Castle ActiveRecord documentation that you may find helpful.
How about adding and removing done within the Teacher Class?
public class Teacher
{
//.... Original implementations
public bool AddCourse(Course course) {
if(_items.Contains(course)) return false;
_items.Add(course);
return true;
}
// similarly for remove course
}
Related
I'm creating an app that returns a list of metals to use in various conditions. I have a Metal class then classes for each type of Metal like Steel, Aluminum, etc. If I have a list of different Steels, I want to first select the best ones based on a set of properties common to all Metals then do a second pass based on the unique properties of Steel. (This isn't my exact problem but my problem is analogous.)
I can't figure out how to pass a List<Steel> to the GetBest() method of the Metal class as shown below that takes its first argument of type List<Metal>. The code won't compile due to error at the line highlighted below with **: "Argument 1: cannot convert from 'System.Collections.Generic.List<Steel>' to 'System.Collections.Generic.List<Metal>'.
public class Metal {
public int PropA { get; set; }
public List<Metal> GetBest( List<Metal> list, int condition1 )
{
var best = new List<Metal>();
//Analysis code here...
return best;
}
}
public class Steel : Metal
{
public int PropB { get; set; }
public List<Steel> GetBest(List<Steel> list, int condition1, int condition2 ) {
var bestSteel = new List<Steel>();
//Do first pass selection based on properties of all metals.
**bestSteel = Metal.GetBest(list, condition1);**
//Do some additional analysis based to Steel's unique properties.
//Analysis code here...
return bestSteel;
}
You could use a constrained generic method:
public static List<T> GetBest<T>(List<T> list, int condition1) where T : Metal
{
var best = new List<T>();
// Analysis code here...
return best;
}
I'm going to answer a different question! A look at how I might approach this problem without confounding my objects (Metal, Steel) with my logic for picking the best metal based on some conditions:
public class Metal{}
public class Steel:Metal{}
public class MetalPickerContext
{
public int Condition1{ get;set;}
}
public class MetalPicker<TMetal, TContext>
where TMetal: Metal
where TContext: MetalPickerContext
{
public virtual IEnumerable<TMetal> GetBest(IEnumerable<TMetal> list, TContext context)
{
var result = new List<TMetal>();
// logic for picking the best metal based on Condition1
return result;
}
}
public class SteelPickerContext: MetalPickerContext
{
public int Condition2{get;set;}
}
public class SteelPicker : MetalPicker<Steel,SteelPickerContext>
{
public override IEnumerable<Steel> GetBest(IEnumerable<Steel> list, SteelPickerContext context)
{
var initialResult = base.GetBest(list,context);
// Having called the base logic apply more with reference to Condition2
return initialResult;
}
}
This compiles (as you can see here) and I could expand the example a bit given some more details to make it a working one. Let me know if that would help you.
I am looking at some legacy code and have come across an abstraction that has properties for each of its derived/concrete types. I cannot share the exact code but please imagine that instead of it being a simple operation that there are numerous operations that are much more complex.
I have not come across anything like this before and have a lot of questions? First, is this a pattern that I am not aware of? If so, what is it? Second question, how should I refactor this so that it follows solid principles?
I will try my best to come up with a better example if needed.
public enum ToolType
{
Unknown = 0,
HRMonitor,
Dumbell,
SomeForceDevice
}
public abstract class ToolData
{
private ToolData()
{
IsValid = false;
this.ToolType = ToolType.Unknown;
}
public ToolData(ToolType toolType)
{
this.ToolType = toolType;
}
public ToolType ToolType { get; }
public virtual bool IsValid { get; protected set; } = true;
public double LinkQuality { get; set; }
public NullToolDataValue NullData => this as NullToolDataValue;
public DumbellDataValue DumbellData => this as DumbellDataValue;
public HeartRateDataValue HRData => this as HeartRateDataValue;
public SomeForceDataValue SomeForceData => this as SomeForceDataValue;
}
public class NullToolDataValue : ToolData
{
public NullToolDataValue() : base(ToolType.Unknown)
{
IsValid = false;
}
}
public class DumbellDataValue : ToolData
{
public double WeightValue { get; private set; }
public DumbellDataValue(double weightValue) : base(ToolType.Dumbell)
{
this.WeightValue = weightValue;
}
public override string ToString()
{
return WeightValue.ToString(CultureInfo.InvariantCulture);
}
}
public class HeartRateDataValue : ToolData
{
public int HeartRate { get; private set; }
public HeartRateDataValue(int heartRate) : base(ToolType.HRMonitor)
{
this.HeartRate = heartRate;
}
public override string ToString()
{
return HeartRate.ToString(CultureInfo.InvariantCulture);
}
}
public class SomeForceDataValue : ToolData
{
public double LeftHandForceValue { get; private set; }
public double RightHandForceValue { get; private set; }
public int LeftHandPosition { get; private set; }
public int RightHandPosition { get; private set; }
public SomeForceDataValue(double lefthandValue, double rightHandValue, int leftHandPosition, int rightHandPosition) : base(ToolType.SomeForceDevice)
{
this.LeftHandForceValue = lefthandValue;
this.LeftHandPosition = leftHandPosition;
this.RightHandForceValue = rightHandValue;
this.RightHandPosition = rightHandPosition;
}
public override string ToString()
{
return $"{LeftHandForceValue.ToString(CultureInfo.InvariantCulture)}" +
$"| {LeftHandPosition.ToString(CultureInfo.InvariantCulture)}" +
$"| {RightHandForceValue.ToString(CultureInfo.InvariantCulture)}" +
$"| {RightHandPosition.ToString(CultureInfo.InvariantCulture)}";
}
}
It is being used/consumed via something like the below which it too is missing some inheritance and things for brevity:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data?.DumbellData == null) return;
//add value to some collection
Collection.Add(data.DumbellData.WeightValue);
}
}
public class HRExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data?.HRData == null) return;
//add value to some collection
Collection.Add(data.HRData.HeartRate);
}
}
Okay, I'm going to give a shot at answering - hopefully this will help.
First up, ToolData shouldn't contain any References/Enums/whatever that list its subtypes. So first on the chopping block: all the lambda properties that cast the object as a specific subtype. I can kinda understand the appeal - you know an instance of ToolType happens to be a FloobieTool, so you call instance.FloobieTool and magically get a FloobieTool cast. But... well, there are problems that come with it, not the least is that you're breaking Opened/Closed Principle. Nothing wrong with making the person calling the class cast it explicitly with (FloobieTool)instance if they know they're working with a FloobieTool.
Next up: the ToolType. Why do you need this? You can tell if your instance of ToolData is a FloobieTool by simply doing an 'is' check in an IF condition:
void SomeFunc(ToolData toolData)
{
if (!(toolData is FloobieTool)) throw new Exception("Non-Floobie!");
// more code
}
I mean, what does that enumeration actually get you? Because it has a definite cost: it has to be kept in-sync with the list of classes that implement ToolData.
Also, the part in ToolDataReceived() for each of those Exercise classes seems... weird. I mean, you've got an exercise, and you're passing in ToolData. Why are you storing the amount of the Dumbell exercise? As opposed to just storing the ToolData. I mean, you're going through quite a bit of testing/casting/etc, just to add the dumbbell weight to a Collection. Any reason you can't just store the ToolData instance and call it a day? If you really need to specifically store Dumbbell info, you could do something like:
public class DumbbellExercise
{
List<DumbbellDataValue> dumbbellData = new List<DumbbellDataValue>();
public void AddToolData(ToolData toolData)
{
if (toolData is DumbbellDataValue)
this.dumbbellData.Add((DumbbellDataValue)toolData);
}
}
Hopefully that helps - it's tough to go into too many details when we're working off an abstracted example of your actual problem :-)
Having seen your edits, I believe even more firmly that the way to refactor this code is to use pattern matching. Pattern matching requires at least C# 7.0 so I'll include an almost-as-good way to do it pre-7.0 versions.
Step 1
Mark the properties obsolete using ObsoleteAttribute and pass true for the error parameter.
[Obsolete("Use pattern matching instead.", true)]
public NullToolDataValue NullData => this as NullToolDataValue;
[Obsolete("Use pattern matching instead.", true)]
public DumbellDataValue DumbellData => this as DumbellDataValue;
[Obsolete("Use pattern matching instead.", true)]
public HeartRateDataValue HRData => this as HeartRateDataValue;
[Obsolete("Use pattern matching instead.", true)]
public SomeForceDataValue SomeForceData => this as SomeForceDataValue;
This will make it a compiler error to use them in any code processed by the compiler. If you're doing any reflection on them, you'll get a runtime exception instead (after step 3 is complete) if you don't also change that code.
Step 2
Modify every call site that uses those properties to use pattern matching instead. If all you're doing is what you showed in the question, is should be as simple as this:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
if (data is DumbellDataValue dumbell)
Collection.Add(dumbell.WeightValue);
// OR
if (!(data is DumbellDataValue dumbell))
return;
Collection.Add(dumbell.WeightValue);
}
}
The second variation is not as pretty because the condition has to be parenthesized before it can be negated (hey, at least VB has the IsNot keyword; go figure) but you get the same early return that the existing code has.
It looks like you're using at least C# 6.0 because you're using the null-coalescing operator (?.), but if you're not using at least 7.0, you can do this, instead:
public class DumbellExcercise
{
public void ToolDataReceived(ToolData data)
{
DumbellDataValue dumbell = data as DumbellDataValue;
if (dumbell != null)
Collection.Add(dumbell.WeightValue);
// OR
DumbellDataValue dumbell = data as DumbellDataValue;
if (dumbell == null)
return;
Collection.Add(dumbell.WeightValue);
}
}
Step 3
Remove the properties. If there are no more compiler errors, the properties aren't being used, so you're free to get rid of them.
Additional Note
The IsValid property has a strange duality to it. It can be assigned by the derived classes but it's also virtual so it can be overridden, too. You really should pick one. If it were my decision, I'd keep it virtual and make it read-only.
public abstract class ToolData
{
// Continue to assume it's true...
public virtual bool IsValid => true;
}
public class NullToolDataValue : ToolData
{
// ...and indicate otherwise as needed.
public override bool IsValid => false;
}
According to DDD principles, external objects should only call methods on an aggregate root, not on other entities in the aggregate, right ?
In case of nested entities, for example: SeatingPlan -> Sections -> Rows -> Seats
SeatingPlan is the aggregate root, while sections, rows and seats are entities that are meaningless outside its parent entity.
Lets say I want to add seats in the seating plan.
I would create SeatingPlan.AddSeat(sectionId, rowId, seatNo) in order to prevent external objects to call SeatingPlan.Sections[x].Rows[y].Seat[s].Add, which is bad, right ?
But still, the AddSeat method of SeatingPlan must delegate the seat creation to the row object, because the seat is a composite of the row, the row owns the seats. So it has to call Sections[x].Rows[y].AddSeat(seatNo).
Now my question is how can I prevent external objects from calling Row.AddSeat method, while allowing the aggregate root to call it ?
internal visibility is too large, even namespace visibility (assuming it would even exists in c#) would be too large. I need an aggregate visibility.
I thought about nesting the class Row in the SeatingPlan class, and making the Row.AddSeat method private. But is it a good practice ? Because the class would have to be public and I remember having read something about it saying that we should avoid public nested classes.
Conflicting domain model role: commands vs queries
I'm suspecting that the reason you allowed external deep navigation of your aggregate root is for querying needs and that's what's causing issues. If you could avoid exposing entities outside the root then this problem goes away. You must not forget that the primary role of the domain model is to process commands while protecting invariants; not fulfilling query needs.
A single model can't be optimized for both, commands & queries. When the model is starting to fail you in one of the two roles it may be time to segregate them. That's called Command Query Responsibility Segregation (CQRS). You'd by-pass the domain model entirely for queries and go straight to the DB, after which you could get rid of most state-exposing members in your aggregate roots.
CQRS scares me...
If you dont want to go that route then you will have to live with the pains of having a single model stretched in different directions. One thing you could do to mitigate the problem you described is to use readonly interfaces, such as IRowView which do not expose any mutating methods. Alternatively, you could also return value objects describing the state of the sub-entity, such as RowDescriptor or RowState. What you will start to realize however is that you will start being forced to invent new concepts that dont exist in your Ubiquitous Language, just to solve technical problems (e.g. preserve encapsulation).
Beware large aggregate roots
The Stadium AR seems to be very large as a consistency boundary. That's usually a good indicator that the boundaries might be wrong. You shouldn't attempt to model the real world: just because a stadium contains sections which have rows, etc., in the real world doesn't mean your model should be composed that way.
Also, dont rely on the rule "A can't exist or doesn't make sense without B" to model aggregates. It's does more harm than good most of the time.
Since that's not the core of the question I'll just leave you to read this excellent Vaughn Vernon article, Effective Aggregate Design.
Firstly I would point out that DDD is a set of guidelines, not rules. Do whatever makes sense in your situation, don't just follow DDD blindly.
That said you can use interfaces/base classes to do what you want. Here is a simple example.
public interface IRow
{
IReadOnlyList<Seat> Seats {get;}
}
public class Stadium
{
private List<Row> _rows = new List<Row>();
public IReadOnlyList<IRow> Rows => _rows;
public void AddSeat(Seat seat, int rowNum) => _rows[rowNum].AddSeat(seat);
private class Row : IRow
{
private List<Seat> _seats = new List<Seat>();
public IReadOnlyList<Seat> Seats => _seats;
public void AddSeat(Seat seat) => _seats.Add(seat);
}
}
In java, I protect the access to internal objects of an aggregate by the scope of those objects. I structure the code so that each aggregate is in a package , named with aggregate name. Internal entities and value objects would be package scoped (no visibility scope keywords when defining them), so that those objects are just accessible from the same package. The aggregate root entity would be public.
According to DDD principles, external objects should only call methods on an aggregate root (AR), not on other entities in the aggregate
Id rather say that an aggregate root is a consistency boundary. That's why "external objects should only call methods on the aggregate root".
On the other hand your value objects (VOs) or entities can be quite rich and encapsulate a lot of their internal rules.
E.g SeatNumber cannot be negative, Seat can have a method Book(Person person) that makes sure that it's booked by only one person, Row can have methods BookASeat(SeatNumber seatId, Person person) and AddASeat(Seat seat), ...
public class Seat : Entity
{
private Person _person;
public Seat(SeatNumber id)
{
SeatId = id;
}
public SeatNumber SeatId { get; }
public void Book(Person person)
{
if(_person == person) return;
if (_person != null)
{
throw new InvalidOperationException($"Seat {SeatId} cannot be booked by {person}. {_person} already booked it.");
}
_person = person;
}
public bool IsBooked => _person != null;
}
I would create SeatingPlan.AddSeat(sectionId, rowId, seatNo) in order to prevent external objects to call SeatingPlan.Sections[x].Rows[y].Seat[s].Add, which is bad, right?
But still, the AddSeat method of SeatingPlan must delegate the seat creation to the row object, because the seat is a composite of the row, the row owns the seats. So it has to call Sections[x].Rows[y].AddSeat(seatNo).
It's not bad to call Sections[sectionNumber].Rows[rowNo].Seat[seat.SeatNo].Add(seat) as long as Sections is a private collection (dictionary) and SeatingPlan doesn't expose it to an outside world.
IMHO: A disadvantage of this approach is the following - all domain rules are maintained by your aggregate root. It cam make you aggregate root too complex too understand or maintain.
In order to keep your aggregate simple I'd recommend to split into multiple entities and make each of them responsible for enforcing their own domain rules:
Row is responsible for maintaining an internal list of its seats, has methods AddASeat(Seat seat) and BookASeat(SeatNumber seatId, Person person)
Section is responsible for maintaining an internal list of rows, knows how to add an entire valid row (AddARow(Row row)) or just to add a seat to an existing row (AddASeat(RowNumber rowId, Seat seat))
Stadium (or a seat plan) can have methods like AddASection(Section section), AddARow(Row row, SectionCode sectionCode), AddASeat(Seat seat, RowNumber rowNumber, SectionCode sectionCode). It all depends on the interface that you provide to your users.
You can describe your aggregate root without exposing internal collections:
/// <summary>
/// Stadium -> Sections -> Rows -> Seats
/// </summary>
public class Stadium : AggregateRoot
{
private readonly IDictionary<SectionCode, Section> _sections;
public static Stadium Create(StadiumCode id, Section[] sections)
{
return new Stadium(id, sections);
}
public override string Id { get; }
private Stadium(StadiumCode id, Section[] sections)
{
_sections = sections.ToDictionary(s => s.SectionId);
Id = id.ToString();
}
public void BookASeat(SeatNumber seat, RowNumber row, SectionCode section, Person person)
{
if (!_sections.ContainsKey(section))
{
throw new InvalidOperationException($"There is no Section {section} on a stadium {Id}.");
}
_sections[section].BookASeat(row, seat, person);
}
public void AddASeat(Seat seat, RowNumber rowNumber, SectionCode sectionCode)
{
_sections.TryGetValue(sectionCode, out var section);
if (section != null)
{
section.AddASeat(rowNumber, seat);
}
else
{
throw new InvalidOperationException();
}
}
public void AddARow(Row row, SectionCode sectionCode)
{
_sections.TryGetValue(sectionCode, out var section);
if (section != null)
{
section.AddARow(row);
}
else
{
throw new InvalidOperationException();
}
}
public void AddASection(Section section)
{
if (_sections.ContainsKey(section.SectionId))
{
throw new InvalidOperationException();
}
_sections.Add(section.SectionId, section);
}
}
public abstract class AggregateRoot
{
public abstract string Id { get; }
}
public class Entity { }
public class ValueObject { }
public class SeatNumber : ValueObject { }
public class RowNumber : ValueObject { }
public class SectionCode : ValueObject { }
public class Person : ValueObject { }
public class StadiumCode : ValueObject { }
public class Row : Entity
{
private readonly IDictionary<SeatNumber, Seat> _seats;
public Row(RowNumber rowId, Seat[] seats)
{
RowId = rowId;
_seats = seats.ToDictionary(s => s.SeatId);
}
public RowNumber RowId { get; }
public void BookASeat(SeatNumber seatId, Person person)
{
if (!_seats.ContainsKey(seatId))
{
throw new InvalidOperationException($"There is no Seat {seatId} in row {RowId}.");
}
_seats[seatId].Book(person);
}
public bool IsBooked(SeatNumber seatId) { throw new NotImplementedException(); }
public void AddASeat(Seat seat)
{
if (_seats.ContainsKey(seat.SeatId))
{
throw new InvalidOperationException();
}
_seats.Add(seat.SeatId, seat);
}
}
public class Section : Entity
{
private readonly IDictionary<RowNumber, Row> _rows;
public Section(SectionCode sectionId, Row[] rows)
{
SectionId = sectionId;
_rows = rows.ToDictionary(r => r.RowId);
}
public SectionCode SectionId { get; }
public void BookASeat(RowNumber rowId, SeatNumber seatId, Person person)
{
if (!_rows.ContainsKey(rowId))
{
throw new InvalidOperationException($"There is no Row {rowId} in section {SectionId}.");
}
_rows[rowId].BookASeat(seatId, person);
}
public void AddASeat(RowNumber rowId, Seat seat)
{
_rows.TryGetValue(rowId, out var row);
if (row != null)
{
row.AddASeat(seat);
}
else
{
throw new InvalidOperationException();
}
}
public void AddARow(Row row)
{
if (_rows.ContainsKey(row.RowId))
{
throw new InvalidOperationException();
}
_rows.Add(row.RowId, row);
}
}
how can I prevent external objects from calling Row.AddSeat method, while allowing the aggregate root to call it ?
If you do not expose a Row or Rows as public property it automatically prevents others from calling it. E.g. in my example only Section has access to its own private collection of _rows and calls method AddSeat on a single row.
If you keep a state of the aggregate root private to itself it means that it can be changed through aggregate root methods only.
This question already has answers here:
Closed 11 years ago.
Possible Duplicate:
Difference between Property and Field in C#
public class Test
{
public bool testData1;
public string testData2;
}
or
public class Test
{
public bool TestData1 { get; set; }
public string TestData2 { get; set; }
}
or
public class Test
{
private bool testData1;
private string testData2;
public bool TestData1 { get { return testData1; } set { testData1 = value; } }
public string TestData2 { get { return testData2; } set { testData2 = value; } }
}
Which optimized code is better or unnecessary? And Why?
Isn't that last one holds a lot unnecessary data?
======= EDIT:
I think in that case:
public class Test
{
public Test(bool testData1)
{
this.testData1 = testData1;
}
private bool testData1;
public bool TestData1 { get { return testData1; } }
public string TestData2 { get; set; }
}
having fields in background is required. Isn't it?
You should not have public fields, use properties instead so you can change the internal implementation later on if neccessary - so 2) wins. 3) is just how auto properties are implemented under the hood so is equivalent to 2)
The second two are equivalent. Just different syntax for saying the same thing.
The first is different- it exposes fields, as opposed to properties. The difference between fields and properties has been covered ad nauseum on the web.
Second and third are same. First is bad, because if you change something (name, type) then you broke class interface.
Using number one in production code should be out of the question, because having public fields is a sure sign of poor use of encapsulation.
The numbers two and three are similar, with one important difference: if you plan to serialize your class, you should prefer #3, because you have tighter control over the variables that you can serialize. Other than that, #2 and #3 are identical. I always start with #2, and go for #3 only when necessary.
The first example is semantically different then the other two.
In the first example, you're using fields instead of properties.
The second example is equivalent to the third; the compiler will generate the backing fields itself. So, the second example is easier to read and imho cleaner.
regarding your editted question:
Not necessarly. You can perfectly do this:
public class MyClass
{
MyClass( bool x )
{
TestData1 = x;
}
public bool TestData1
{
get;
private set;
}
}
I want to be able to create "Transformation" classes that take a given object, perform a series of transformations on it (i.e. change property values) and keeps track of the transformations performed. The transformation performed will vary based on the properties of the object provided.
I want to be able to apply transformation rules (which are finite and commin) within a given transformation class using a fluent style interface.
At a high level, I understand that I will likely have an ITransformer, an ITransformationRule, and ITransformationResult, and a few other objects to make this happen.
How I would want the code to work when creating Transformation classes...
public OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
public OfflinePersonToOnlineTransformation()
{
Transform(x => x.PersonClassification)
.WhenCreatedBefore("1/1/2000")
.ClassifyAs("Online");
}
}
I understand that my TransformerBase would need to implement the "Transform" method that takes a Func or Expression, and I understand that it would need to keep a collection of ITransformationRules. I also understand that I would likely use Extension methods for the "WhenCreatedBefore" and "ClassifyAs" methods.
The trouble is, I can't figure out how to make it all work. I've looked at source code for Fluent Validation .NET as it does validation this way, but the complexity is killing me. I'm looking for a tutorial that covers this, or someone to spell it out in a way that is a pretty straightforward.
Thanks in advance.
Not quite sure why you want to go to all this effort when linq does most of it for you:
IEnumerable<Person> somePeople; // from wherever
somePeople.Where(x => x.CreateDate < new DateTime(2000,1,1))
.ForEach(x => x.PersonClassification = "Online");
Simply by adding the ForEach from here noting the proisos for why it's not included by default.
If you want to make the WhereCreatedBefore nicer then a simple extension like so:
static class PersonExtensions
{
public static bool WhereCreatedBefore(this Person p,
int year, int month, int day)
{
return p.CreateDate < new DateTime(year,month,day);
}
}
which is useful in and of itself and gives you:
somePeople.Where(x => x.CreatedBefore(2000,1,1))
.ForEach(x => x.PersonClassification = "Online");
Why limit yourself when simply expanding on the tools linq gives you makes things easier.
If you want to chain multiple side effects a simple alteration of ForEach like so:
public static IEnumerable<T> Modify<T>(
this IEnumerable<T> input, Action<T> action)
{
foreach (var x in input)
{
action(x);
yield return x;
}
}
giving you:
somePeople.Where(x => x.CreatedBefore(2000,1,1))
.Modify(x => x.PersonClassification = "Online");
.Modify(x => x.LastModifiedBy = Environment.UserName);
Or if you use the language integrated part of it:
(from p in somePeople where p.CreatedBefore(2000,1,1)) select p)
.Modify(p => p.PersonClassification = "Online");
.Modify(p => p.LastModifiedBy = Environment.UserName);
IF you really* wanted to you could write a ClassifyAs extension like so:
public static IEnumerable<Person> ClassifyAs(
this IEnumerable<Person> input, string classification)
{
foreach (var p in input)
{
p. PersonClassification = classification;
yield return p;
}
}
giving you your original of:
(from p in input where p.CreatedBefore(2000,1,1)) select p).ClassifyAs("Online");
Which is a one liner! with no fancy frameworks or type hierarchies required, just some useful extension methods.
Linq is generally well designed, well implemented, ubiquitous and well integrated into c#. Reimplementing the query parts of it would be foolish and wasteful, what you want is to add side effect causing operations to it. This is fine (you have mutable objects so this is hardly causing a problem) just add those operations. Just making them continue to yield their input will make your code fluent in style.
I had a think; Its only pseudo code but does this help?
public interface IPerson {
string PersonClassification { get; set; }
DateTime CreateDate { get; set; }
}
public class Person : IPerson {
public string PersonClassification { get; set; }
public DateTime CreateDate { get; set; }
}
public class TransformerBase<T>
where T : IPerson {
T Person { get; set; }
T Transform(Func<T, PersonClassification> transformer) {
return transformer(person);
}
}
public class OfflinePersonToOnlineTransformation : TransformerBase<Person>
{
public OfflinePersonToOnlineTransformation()
{
Transform(x => x.PersonClassification)
.WhenCreatedBefore("1/1/2000")
.ClassifyAs("Online");
}
}
public static class Extensions {
public static T WhenCreatedBefore<T>(this T person, string date) where T : IPerson{
if(person == null || person.CreateDate > DateTime.Parse(date))
return null
return person;
}
public static T Classify<T>(this T person, string classification)where T : IPerson{
if(person != null)
person.PersonClassification = classification;
return person;
}
}
It might help to take a step back and write a simple fluent interface first. You don't need generics or multiple classes to implement one. The main benefit of the fluent interface pattern is easy to read code. It's accomplished by returning this from methods to promote method chaining. Here's a basic example. I would start here and work backward to your desired result.
public partial class Form1 : Form
{
public Form1()
{
InitializeComponent();
}
class Calculator
{
List<int> values = new List<int>();
public Calculator Add(int value)
{
values.Add(value);
return this;
}
public int Count()
{
return values.Count;
}
public int Sum()
{
return values.Sum();
}
}
private void Form1_Load(object sender, EventArgs e)
{
//returns 3
int sum =
new Calculator()
.Add(1)
.Add(2)
.Sum();
}
}