问题
I'm building an ordering system. And here I have an Order
class, which has a property named OrderNumber
. As you know, OrderNumber
can only be assigned once, so I don't want to make it public
(so I made it private
).
However, the order number is generated according to a sequencial value stored in database.
For example, the value in database is 10, now I genearte an order number, the order number will be "Year-Month-10
", and the value will increase to 11. The value will be reset every month.
You see, the order number generation has a dependency to database. If I make OrderNumber
private
, I can only call the generate order number method in the Order
class (maybe in the constructor), that's not good and hard to do unit testing. And, I don't want to use any ServiceLocator
in the Order
class, I think it's bad too.
If I make the order number public
, the problems above can be resolved. But the order number might be changed by some coders' mistake now, it's not safe.
So, can I make the OrderNumber
property public? And your reasons?
Updates:
Thanks to Yahia for giving me a hint. Now I consider making OrderNumber property readonly, and pass the generator (e.g. IOrderNumberGenerator) to the constructor of the Order class.
But there's another problem: In my senario, the order number is not assigned when the Order object is created. The customer can create and save an order without passing the order to the order verifier. So before the order is passed to the order verifier, the order number is not assigned. OrderNumber is assigned only when the customer click the "Request Order Verification" button, and then the OrderNumber cannot be changed again. And the workflow moves to the next step (Order Verification).
I've created a new question, please look here: Design Decision: Generate OrderNumber which depends on a database value
BTW: I'm using C#
Thanks!
回答1:
I would recommend having a public readonly property OrderNumber
(i.e. make set
private) based on a private field... this gives you the benefits of both without any negative aspects.
Something you should consider:
Cases like the ones you describe are usually solved by implementing the Factory pattern...
EDIT - regarding the update of the OP:
Make a class OrderNumber
and put it as a public property into your Order
class.
The OrderNumber class
has only private constructor and is only created via Factory pattern.
Thus your Order
has initially null
assigned to the OrderNumber
property... this property has a private set
method which only allows assignment when the internal field is null
... to assign an OrderNumber
you have for example a Status
property which when changed to Order Verification
calls the saved reference to IOrderNumberGenerator
(from the constructor) and set the OrderNumber
once...
回答2:
Remember, you can set the visibility of the get/set methods of a property:
public class Order
{
private string orderNumber_;
public string OrderNumber
{
get { return orderNumber_; }
private set { orderNumber_ = value; }
}
}
Update
Given your requirement, why not implement a second constructor, that takes an order number generator and an existing order?
public interface IOrderNumberGenerator
{
string Generate();
}
public class Order
{
private string orderNumber_;
// default ctor
public Order()
{
} // eo ORder
public Order(IOrderNumberGenerator generator, Order order)
{
orderNumber_ = generator.Generate();
/* copy other fields from the existing Order*/
}
public string OrderNumber
{
get { return orderNumber_; }
}
} // eo class Order
来源:https://stackoverflow.com/questions/7885931/design-decision-ordernumber-property-in-order-class-public-or-private