|
You could make the method name more specific in this case: DoSomethingToB
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
-sniff- -sniff-
I smell a homework or test question.
|
|
|
|
|
Not illegal.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Thanks for all your replys,
but I cannot change the method name as DoSomethingToB
for example, the following method will calculate total price and update it to repository,
but also update the Customer c , such as
--Customer.Points
--Customer.Role
depended on the amount he bought:
public void SetTotalPrice(ShoppingCart s, Customer c, List<Product> lp)
and the caller of the method will use Customer.Points and Customer.Role to do other calculation.
Therefore, I cannot change the method name because its purpose is about total price,
the updated of Customer c is a side effect
I think, in OO design, the above SetTotalPrice() method is not appropriate, isn't it?
|
|
|
|
|
codecs1 wrote: the following method will calculate total price and update it to repository, To be strictly OO a method should only have one job. In this case to set the total price. Updating the repository should be a different method.
|
|
|
|
|
Yes, In OO, one method should only have one job,
Assume SetTotalPrice() has just one job: set the total price.
However, at the same time, it also produces some values of Customer .
I think there is no reason to calculate the Customer one more time after SetTotalPrice() called.
And the caller of SetTotalPrice() just uses the updated Customer logically
Therefore, I hope to know how to handle such circumstance in OO practice, Thanks!! 
modified 3-Apr-21 23:35pm.
|
|
|
|
|
codecs1 wrote: I think there is no reason to calculate the Customer one more time
Err...yes that actually is a problem.
You are suggesting that you should program to convenience rather than to design. This it same ideology that leads programmers to start making base classes for everything for functional reasons and ignoring the "is a" design principle (and leading to highly coupled software as well.)
There are other ways to handle redundant functionality versus attempting to insert it in methods for convenience.
|
|
|
|
|
This still seems a strange approach. Generally, it is good to make methods as functional as possible - in the sense that we should generally avoid updating parameters within methods.
In this case, the process being performed by 'SetTotalPrice' doesn't meet the requirement of being an expected result. The method describes setting the price, but not the fact that the operation affects the value of the customer.
Consider moving some of the behaviour into another method or class, representing the process as a whole.
If the whole thing is to process an Order for example, so 'SetTotalPrice' calculates the total price, then the part to deal with Points and Roles should reside elsewhere, and the process of updating them should be part of, for example, the ProcessOrder method that in turn calls SetTotalPrice.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
Alan Kay.
|
|
|
|
|
Quote: in which, many of properties of Object B b will be modified in DoSomething()
To be honest situations like this are the reason why people start bragging that OOP is a problem and you should stick to FP. I mean it's hard to reason about what the B will after it gets processed by DoSomething . The same way what A and C will become.
This is the reason why I'm a proponent of the second option but to return the copy of the input without changing the input itself. Although it seems more functional at least it tells "hey here's new B for you but in case you'll need original values you may use them as well".
Alternatively, you may go with the first option. IMO void return type tells "be prepared that input parameters may be changed unpredictably"
|
|
|
|
|
"IMO void return type tells "be prepared that input parameters may be changed unpredictably"
For methods, I'd normally expect a method returning nothing to update the object itself, not the other parameters.
"If you don't fail at least 90 percent of the time, you're not aiming high enough."
Alan Kay.
|
|
|
|
|
How about two objects acting as input parameters? Which of them do you expect to be updated?
|
|
|
|
|
Assume there is a method which return the query result List<Student>
List<Student> FindStudents(StudentCriteria sc); in which the StudentCriteria is a model for passing the search information:
public class StudentCriteria
{
public string Name { set; get; }
public int? Age { set; get; }
public DateTime? BeginRegisterDate { set; get; }
public DateTime? EndRegisterDate { set; get; }
}
Moveover, we should validate the input parameter StudentCriteria , so we call the following method in FindStudents(...)
ValidationResult Validate(StudentCriteria sc); in which ValidationResult is an object representing the validation result, something like that:
public class ValidationResult
{
public bool Success { set; get; }
public List<String> ErrorInfo { set; get; }
}
All 'Error' information will be contained in ValidationResult and return to FindStudents(...) if Validate(...) finds any problem in StudentCriteria sc :
such as Age is negative int, EndRegisterDate is before BegionRegisterDate...
But, how can FindStudents(...) return the ValidationResult to the caller?
-----Someone may consider that FindStudents(...) throws ArgumentException to the caller if StudentCriteria sc is invalid....
However, I think Exceptions are for exceptional circumstances
|
|
|
|
|
I see no point in "validation" when you're in the "data access / model layer"; all data should have been validated before that.
You return a list; with items or empty (if nothing found / returned). That's it.
(Database server issues are handled in their own layer.)
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
For a start you are not validating the result, you are validating the criteria!
So
ValidateCriteria can return a string (empty if valid else the error info) OR a bool and the method itself informs the user of the error info.
Then if the Criteria is valid pass it to the database for search and if it returns an empty list then there is no such student.
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|
|
public class StudentCriteria
{
public string Name { set; get; }
public int? Age { set; get; }
public DateTime? BeginRegisterDate { set; get; }
public DateTime? EndRegisterDate { set; get; }
public ValidationResult Validate ()
{
ValidationResult result = new ValidationResult();
if (Age > 0)
result.ErrorInfo.Add("Nope, too young.");
return result;
}
}
public class ValidationResult
{
public bool Success { get { return Convert.ToString(ErrorInfo).Length > 0; } }
public List<String> ErrorInfo { set; get; }
}
codecs1 wrote: All 'Error' information will be contained in ValidationResult and return to FindStudents No.
You may validate you search-criteria, but "FindStudents" should not be linked to that. Reading from a db has nothing to do with search-criteria. Decouple those. Before calling "FindStudents", confirm and validate your input, before passing to a database.
Bastard Programmer from Hell
"If you just follow the bacon Eddy, wherever it leads you, then you won't have to think about politics." -- Some Bell.
|
|
|
|
|
Thanks for all your replies!! I have gotten the idea that the caller must validate the data first.
But if it is a DLL static method for providing services to the upper presentation layer such as Winform, Webform, Asp.net Mvc, WCF or WPF:
public static List<Student> FindStudents(StudentCriteria sc); The presentation layer has no any idea or logic on the Student and also StudentCriteria .
It just calls the static service using the information such as age or Name to get List<Student>
If you are the developer of such service layer, how do you design the signature of the stateless
method FindStudents(...) ?
(i.e. For the service consumer, All he needs to know is just to call one service and get the data)
modified 14-Mar-21 21:23pm.
|
|
|
|
|
|
Your reply is exactly what I concern and need.
Thanks Richard
By the way, the article provided is too difficult for me
so I need to study more in C# syntax first.
|
|
|
|
|
what is types of Architecturel rendering ?
|
|
|
|
|
|
I'll try to keep the example simple. I am wondering if we should store data differently so that reporting might be easier. For example, let's say we log when a user logs in and out. A normal sql table might look something like this:
user_id | action | log_date |
---|
1 | Login | 2021-01-01 8:00 AM | 1 | Logout | 2021-01-01 5:00 PM
| 1 | Login | 2021-01-02 8:00 AM | 1 | Logout | 2021-01-02 10:00 AM | 1 | Login | 2021-01-02 12:00 PM | 1 | Logout | 2021-01-01 5:00 PM |
So on and so forth.
Let's say the business needs a report of how long each user is logged in each day. I'm pretty sure I could figure out some sql that uses row_number and partitioning and subtract previous value to end up with the difference between each login and logout event and sum for each day. (Ignore night shifts that might start in the evening and run over to the next day.)
However, we don't want to be writing reports but using an ad-hoc report engine, such as PowerBi.
1) Can a reporting engine take the table of data and allow the user to run a report that shows how long each user is logged in each day?
2) As developers, should we store the data differently to make those types of reports easier? Maybe have a separate summary table?
I know PowerBi pretty well but I don't know how to do a report of how long each user is logged in based on just this table of data.
Should we as developers store the data differently, or is it up to the report (BI) side to manipulate the raw data? Thoughts and opinions?
|
|
|
|
|
It's the difference between an "operational" system versus an "informational" system.
Operational / transaction systems are optimized for day-to-day usage.
An informational system (e.g. a "data warehouse" / DW) is designed specifically for info retrieval and could include redundant data to facilitate querying. The data in the info system is extracted from the operational systems.
The operational system may span a year, more or less. The DW could span decades.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
If I understand you correctly, keep logging it the way we are but we may need a separate system (data warehouse) to make reporting easier.
Thanks for the feedback.
|
|
|
|
|
Correct. You may also not want "ad hoc users" hammering the operational system with inefficient queries that impact overall performance of the day-to-day.
It was only in wine that he laid down no limit for himself, but he did not allow himself to be confused by it.
― Confucian Analects: Rules of Confucius about his food
|
|
|
|
|
And now it becomes a design issue, do you store the DW data in a denormalised structure (this is standard practice for a DW) do you then write 2 distinct reports targeting each system.
How often do you transfer data to the DW?
How often do you purge data from the production system?
Never underestimate the power of human stupidity -
RAH
I'm old. I know stuff - JSOP
|
|
|
|