Eliminate complex if else through proper software engineering principles - oop

A CRM System exists where lets say there are 60 different order types for 40 different products. Processing of each order for each product is different though there may be similarities. Code for the process logic of these orders involves complex if else statements. Change in a code is extremely risky as it often breaks consistency somewhere else because of long and complex if else. It is very hard for the developer to keep track of if else.
How can the system be designed with OOP principles or otherwise, so that we can limit the the effect of code change only to that order type and product.
Update:
We sell Service(s). Services can be combined and called Bundle. Services are customizable and subcomponents can be added to it as well.
At the point of buying Services or modifying existing Services, Order is raised with the customized components specified as OrderItems. Of the OrderItems, some are MainOrderItem and rest are related to one of the MainOrderItem (Remember Bundle Services). MainOrderItem directly relates to specific Service. Other OrderItem relates to the selected subcomponents. Each OrderItem has its own Attributes and Resources.
Orders are processed differently based on Order Type. Processing of Order is in several stages that may sometimes take a day or two. The complex logic is at this point where if else conditional check happens for 40 different Order Types for 60 different Services
What in my mind is that to have the processing logic of different Order Types and Services in different classes (40 * 60 Classes) and somehow link them. At the starting point of Order processing, based on the Service and Order Type program should resolve the object of the specific class to process the order and that is the only condition check occurs. Distinct processing logic is encapsulated inside specific classes. So there is no mix in processing logic of Orders and Services. But there are some common logic shared between multiple Orders and Services which I don't want to duplicate in different classes. All of this combined is where I am looking for Ideas, Concepts and Patterns (Strategy?, Template Method?, etc...).

Below is just a naive example for illustration how you could approach your problem. Example takes into account only Service not Order Type as that is too vague in your question. I agree with comments below your question, that some more details are needed.
using System;
using System.Collections;
using System.Collections.Generic;
using System.Linq;
public class Program
{
public static void Main()
{
// Set-up services
var availableServices = new[]{
new Service{ServiceId = 1, Name = "Consulting"},
new Service{ServiceId = 2, Name = "Marketing"}
};
// Set-up processors (aka DI container)
var processors = new Dictionary<int, IOrderProcessor>
{
{1, new ConsultingServiceProcessor()},
{2, new MarketingServiceProcessor()}
};
// Generate orders
var randOrderNumber = new Random();
var listoOfOrders = availableServices
.Select(s => new Order{
Service = s,
OrderNumber = randOrderNumber.Next(1000, 9999)
})
.ToList();
// Process orders
listoOfOrders
.ForEach(order =>
processors[order.Service.ServiceId]
.Process(order));
}
public class Service
{
public int ServiceId {get;set;}
public string Name {get;set;}
}
public interface IOrder
{
int OrderNumber {get;set;}
Service Service {get;set;}
}
public class Order : IOrder
{
public int OrderNumber {get;set;}
public Service Service {get;set;}
}
public interface IOrderProcessor
{
void Process(IOrder order);
}
public abstract class BaseOrderProcessor : IOrderProcessor
{
// Common data
public virtual void Process(IOrder order)
{
// Common logic
Console.WriteLine(string.Format("Base logic executed for order nr. {0}", order.OrderNumber));
}
protected int CommonMethod()
{
return 1;
}
// Common internal logic
}
public class ConsultingServiceProcessor : BaseOrderProcessor
{
// Service specific implementation
public override void Process(IOrder order)
{
// Service specific logic
base.Process(order); // skip if not needed
var commonValue = CommonMethod();
Console.WriteLine(string.Format("Consuling logic executed for order nr. {0}", order.OrderNumber));
}
}
public class MarketingServiceProcessor : BaseOrderProcessor
{
// Service specific implementation
public override void Process(IOrder order)
{
// Service specific logic
base.Process(order); // skip if not needed
var commonValue = CommonMethod();
Console.WriteLine(string.Format("Consuling logic executed for order nr. {0}", order.OrderNumber));
}
}
}

At a high level of abstraction, what you want to do is isolate parts of the code that vary independently in Abstractions.
So the question is, among 40 OrderType what differs and amongst 60 Service what differs ?
If the answer is we have large portfolio and it's okay to maintain 40 + 60 cases, there remains the question of combinations, 40 * 60 is huge.
So you need to refine and express how may Services interact with products, are there only a few classes of interaction, or are all 40*60 cases different ?
Possibly you want a Strategy with quite a few operations on the Abstract strategy, and then you Decorate it to express Services, as they can be combined this approach offers nice layering features.
The product itself might override some behaviors, perhaps a Bridge which is basically a Strategy++ would fit here (services vary independently from Products).

Related

When is casting/instanceof a good use?

Every time I google instanceof and casting I will always see answers saying to avoid it and use X pattern.
I have an example where I can't see any pattern I think I could use.
We have 2 classes: Order and Payment (CashPayment and CardPayment).
CashPayment has 1 property called amount and and an implemented method pay.
CardPayment has 1 property called cardNumber and an implemented pay that calls 3rd party API.
Now say you would like to compose a view about an Order, how would someone avoid using instanceof or casting here to show the payment details?
With instanceof I can do this:
order = new Order(...);
order.checkout(aPayment);
Payment Details (Cash):
Type: (instanceof CashPayment ? "Cash") or order.payment().type();
Amount: ((CashPayment) order.payment()).amount();
Payment Details (Card):
Type: (instanceof CardPayment ? "Card") or order.payment().type();
Card Number: ((CardPayment) order.payment()).cardNumber();
Question: can we really avoid instanceof and casting? If yes, how can we achieve this the "OO-way"? If no, I assume this is one of the valid cases?
IMO, we can avoid instanceof/casting and favor use of overridden methods however if you want to know about a concrete object it can't be avoided.
Edit:
I am trying to write my Domain Models which means it is agnostic of infrastructure and application specific stuff.
Imagine we would need to save the Order thru OrderRepository and the Payment has their own tables. Wouldn't it be ugly if it was like:
class OrderRepository {
public function save(Order order) {
// Insert into order query here...
// Insert into orderItems query here...
// Insert payment into its table
queryBuilder
.table(order.payment().tableName())
.insert([
order.payment().columnName() => order.payment().value()
]);
}
}
If you absolutely want to segregate the operation from the object itself (e.g. to maintain separation of concerns), but the operation is strongly coupled to subclass details then you only have two choices.
You either need to rethink the model and find an homogeneous abstraction, which could be any approach that allows you to treat the various types the same way.
e.g.
Payment Details:
Type: {{payment.type}}
{{for attr in payment.attributes}}
{{attr.name}}: {{attr.value}}
{{/}}
or you need to perform some kind of type matching, whether you are using the visitor pattern, pattern matching, instanceof, etc.
e.g. with the Visitor Pattern
interface IPaymentVisitor {
public void visit(CashPayment payment);
public void visit(CardPayment payment);
}
class PaymentRenderer implements IPaymentVisitor ...
class CashPayment extends Payment {
...
public void visit(IPaymentVisitor visitor) {
visitor.visit(this);
}
}
var renderer = new PaymentRenderer(outputStream);
payment.accept(renderer);
The obvious object-oriented solution is to add a display() method to the Payment.
In general instanceof/casting is frowned upon, because it usually indicates a less then optimal design. The only time where it is allowed is when the type-system is not powerful enough to express something. I encountered a few situations in Java where there is no better solution (mostly because there are no read-only collections in Java, therefore the generic parameter is invariant), none in Scala or Haskell yet.
You could go with composition over inheritance.
Perhaps something along the lines of:
public class Payment
{
private CardPaymentDetail _cardPaymentDetail;
public PaymentType Type { get; private set; }
public decimal Amount { get; }
private Payment(decimal amount)
{
// > 0 guard
Amount = amount;
}
private Payment(decimal amount, CardPaymentDetail cardPayment)
: this(amout)
{
// null guard
CardPayment = cardPayment;
}
public CardPaymentDetail CardPayment
{
get
{
if (Type != PaymentType.Card)
{
throw new InvalidOperationException("This is not a card payment.");
}
return _cardPaymentDetail;
}
}
}
IMHO persistence may also be easier. Along the same lines I have also used what equates to an Unknown payment type as the default and then have a method to specify the type: AsCard(CardPaymentDetail cardPayment) { }.

How to model Region and a point in that region?

I need to model a Region that has a contains(point) method. That method determines whether a point falls within the boundaries of the Region.
I currently see two implementations of Region:
One where the region is defined by a start and end postalcode.
One where the region is defined by a lat/lng and a radius.
Now, my main problem is how to define the interface for the contains() method.
Possible solution #1:
One easy solution is to let a point also be defined by a Region:
PostalcodeRegion implements Region
region = new PostalcodeRegion(postalStart: 1000, postalEnd: 2000);
point = new PostalcodeRegion(postalStart: 1234, postalEnd: 1234);
region.contains(point); // true
The interface could look like this:
Region
+ contains(Region region):bool
The problem with this is that the contains() method is not specific, and that we abuse Region to let it be something it is not: a Point.
Possible solution #2:
Or, we define a new point class:
PostalcodeRegion implements Region {}
PostalcodePoint implements Point {}
region = new PostalcodeRegion(postalStart: 1000, postalEnd: 2000);
point = new PostalcodePoint(postalCode: 1234);
region.contains(point); // true
Interface:
Region
+ contains(Point point)
There are several problems with this method:
contains() method is still not specific
There is a pointless Point concept. In and of itself it is/does nothing, it is just a marker interface.
Clarification:
Ok, so this is the first time I encounter where I provide my line of thinking, in the form of possible solutions, that is actually counter productive. My apologies.
Let me try and describe the use case: The system this use case is part of is used to handle insurance claims (amongst other things). When someone claims water damages from a leaking pipe f.e., this system handles the entire workflow from entry by the customer, all the way to sending a repair company etc to close the file.
Now, depending on circumstances, there are two ways to find eligible repair companies: by postal code, or by lat lng.
In the first case (postal code), we could find eligible repair companies with the following code:
region = new PostalCodeRegion(customer.postalCode - 500, customer.postalCode + 500)
region.contains(new PostalCodePoint(repairCompany1.postalCode))
region.contains(new PostalCodePoint(repairCompany2.postalCode))
Or, in the second case:
region = new LatLngRegion(customer.latLng, 50) // 50 km radius
region.contains(new LatLngPoint(repairCompany1.latLng))
region.contains(new LatLngPoint(repairCompany2.latLng))
I want to be able to safely pass around Regions and Points, so I can make sure they are Regions and Points. But I don't actually care about their sub-types.
One thing I would like, but I am not sure it is possible, is to not have to do a runtime check on the passed point in the contains() method. Preferably it would be enforced by contract that I get the correct data (fitting to the chosen Region implementation) to work with.
I'm mostly just thinking out loud. I am inclined to go with method #2, and do a runtime type check of the passed point var in contains() implementation.
I would like to hear some thoughts over one or the other, or even better: a new suggestion I haven't thought of.
It shouldn't be really relevant, but the target platform is PHP. So I can't use generics for example.
Given that a Region would have to operate on two abstractions that have nothing in common (Point and Postcode) then a generic interface is one way of crafting a clean strongly typed common interface, but you should question whether that abstraction is useful to model or not. As developers it's easy to get lost in too much abstractions e.g. maybe a Region<T> is just a Container<T>, etc. and all of a sudden the concepts you work with are nowhere to be found in your domain's Ubiquitous Language.
public interface Region<T> {
public boolean contains(T el);
}
class PostalRegion implements Region<Postcode> {
public boolean contains(Postcode el) { ... }
}
class GeographicRegion implements Region<Point> {
public boolean contains(Point el) { ... }
}
The issue with such question is that it's focusing on how to achieve a specific design rather than explaining the real business problem and that makes it difficult to judge whether or not the solution is appropriate or which alternate solution would.
How would the system leverage the common interface if such interface was implemented? Would it make the model easier to work with?
Since we are forced to assume a problem domain, here's a fictional scenario about developing a city zonage system (I know nothing about this domain so the example may be silly).
In the context of city zonage management, we have uniquely
identified regions that are defined by a postal code range and a
geographical area. We need a system that can answer whether or not a
postal code and/or a point is contained within a specific region.
That gives us a little more context to work with and come up with a model that can fulfill the needs.
We can assume that an application service such as RegionService could maybe look like:
class RegionService {
IRegionRepository regionRepository;
...
boolean regionContainsPoint(regionId, lat, lng) {
region = regionRepository.regionOfId(regionId);
return region.contains(new Point(lat, lng));
}
boolean regionContainsPostcode(regionId, postcode) {
region = regionRepository.regionOfId(regionId);
return region.contains(new Postcode(postcode));
}
}
Then, maybe the design would benefit from applying the Interface Segregation Principle (ISP) where you'd have a Locator<T> interface or explicit PostcodeLocator and PointLocator interfaces, implemented either by Region or other services and used by the RegionService or be a service of their own.
If answering the questions requires complex processing, etc. then maybe the logic should be extracted from a PostalRange and an Area. Applying the ISP would help keeping the design more flexible.
It's important to note that a domain model shines on the write side to protect invariants and compute complex rules & state transitions, but querying needs are often better expressed as stateless services that leverages powerful infrastructure components (e.g. database).
EDIT 1:
I had not realized you mentioned "no generics". Still leaving my answer there b/c I think it still gives good modeling insights and warns about not so useful abstractions. Always think about how the client will be using the API as it helps to determine the usefulness of an abstraction.
EDIT 2 (after clarification added):
It seems that the Specification Pattern could be a useful modeling tool here.
Customers could be said to have a repair company eligibility specification...
E.g.
class Customer {
...
repairCompanyEligibilitySpec() {
//The factory method for creating the specification doesn't have to be on the Customer
postalRange = new PostalRange(this.postalCode - 500, this.postCode + 500);
postalCodeWithin500Range = new PostalCodeWithinRange(postalRange);
locationWithin50kmRadius = new LocationWithinRadius(this.location, Distance.ofKm(50));
return postalCodeWithin500Range.and(locationWithin50kmRadius);
}
}
//Usage
repairCompanyEligibilitySpec = customer.repairCompanyEligibilitySpec();
companyEligibleForRepair = repairCompanyEligibilitySpec.isSatisfiedBy(company);
Note that I haven't really understood what you mean by "I want to be able to safely pass around Regions and Points" or at least failed to understand why this requires a common interface so perhaps the proposed design wouldn't be suitable. Making the policy/rule/spec explicit has several advantages and the specification pattern is easily extensible to support features such as describing why a company was not eligible, etc.
e.g.
unsatisfiedSpec = repairCompanyEligibilitySpec.remainderUnsatisfiedBy(company);
reasonUnsatisfied = unsatisfiedSpec.describe();
Ultimately the specification itself doesn't have to implement the operations. You could use the Visitor Pattern in order to add new operations to a set of specifications and/or to segregate operations by logical layer.
I think it's better not to have the implementation of contains in the data object and to create a seperate class for each of the contains implementations. Something like:
class Region
{
...
}
class RegionCheckManager
{
function registerCheckerForPointType(string $pointType, RegionCheckerInterface $checkerImplementation): void
{
...
}
function contains(PointInterface $point, Region $region): bool
{
return $this->getCheckerForPoint($point)->check($region, $point);
}
/** get correct checker for point type **/
private function getCheckerForPoint(PointInterface $point): RegionCheckerInterface
{
...
}
}
interface RegionCheckerInterface
{
public function contains(PointInterface $point): bool;
}
class PostcodeChecker implements RegionCheckerInterface
{
...
}
class PointChecker implements RegionCheckerInterface
{
...
}
Postcode and Point are different conceptual things, they are two different types. Postcode is a scalar value, Point is a geographic item. In fact, your PostalCodeRegion class is a range of scalar value, your LatLngRegion class is a geographic area that has center coordinates and radius. You try to combine two incompatible abstractions. Attempt to make one interface for two absolutely different things is the wrong way which leads to unobvious code and implicit abstractions. You should rethink your abstractions. For example:
What is a postcode? It is a positive number in the simplest case. You can create a Postcode class as a value object and implement simple methods to work with its data.
class Postcode
{
private $number;
public function __constuct(int $number)
{
assert($value <= 0, 'Postcode must be greater than 0');
$this->number = $number;
}
public function getNumber(): int
{
return $this->number;
}
public function greatOrEqual(Postalcode $value): bool
{
return $this->number >= $value->getNumber();
}
public function lessOrEqual(Postalcode $value): bool
{
return $this->number <= $value->getNumber();
}
}
What is a postcode range? It a set of postcodes that contains start postcode and end postcode. So you can also create a value object of a range and implement contains method in it.
class PostcodeRange
{
private $start;
private $end;
public function __construct(Postcode $start, Postcode $end)
{
assert(!$start->lessOrEqual($end));
$this->start = $start;
$this->end = $end;
}
public function contains(Postcode $value): bool
{
return $value->greatOrEqual($this->start) && $value->lessOrEqual($this->end);
}
}
What is a point? It is a geographic item that has some coordinates.
class Point
{
private $lan;
private $lng;
public function __constuct(float $lan, float $lng)
{
$this->lan = $lan;
$this->lng = $lng;
}
public function getLan(): float
{
return $this->lan;
}
public function getLng(): float
{
return $this->lng;
}
}
What is an area? It is a geographic region that has some borders. In your case, those borders defined with a circle that has a center point and some radius.
class Area
{
private $center;
private $radius;
public function __constuct(Point $center, int $radius)
{
$this->center = $center;
$this->radius = $radius;
}
public function contains(Point $point): bool
{
// implementation of method
}
}
So, each company has a postcode and some location defined by its coordinates.
class Company
{
private $postcode;
private $location;
public function __construct(Postcode $postcode, Point $location)
{
$this->postcode = $postcode;
$this->location = $location;
}
public function getPostcode(): Postcode
{
return $this->postcode;
}
public function getLocation(): Point
{
return $this->location;
}
}
So, how you said you have a list of companies and try to find it by postcode range or area. So you can create company collection which can contain all companies and can implement algorithms to search by necessary criteria.
class CompanyCollection
{
private $items;
public function __constuct(array $items)
{
$this->items = $items;
}
public function findByPostcodeRange(PostcodeRange $range): CompanyCollection
{
$items = array_filter($this->items, function(Company $item) use ($range) {
return $range->contains($item->getPostcode());
});
return new static($items);
}
public function findByArea(Area $area): CompanyCollection
{
$items = array_filter($this->items, function(Company $item) use ($area) {
return $area->contains($item->getLocation());
});
return new static($items);
}
}
Example of usage:
$collection = new CompanyCollection([
new Company(new Postcode(1200), new Point(1, 1)),
new Company(new Postcode(1201), new Point(2, 2)),
])
$range = new PostcodeRange(new Postcode(1000), new Postcode(2000));
$area = new Area(new Point(0, 0), 50);
// find only by postcode range
$collection->findByPostcodeRange($range);
// find only by area
$collection->findByArea($area);
// find by postcode range and area
$collection->findByPostcodeRange($range)->findByArea($area);
If I understand the problem correctly, you have some module M, which needs to accept some 3 objects:
implementation of region (postcodes vs radius, let's call them R1 vs R2)
implementation of point (postcode vs lat/lng, P1 vs P2)
some API C to check the point is within the region
and it then applies the 3rd object on the first 2.
(Could be that C is R1 or R2, that's immaterial for the problem definition).
So spelling out the problem: you can apply C on R1+P1 or R2+P2, but not R1+P2 or R2+P1.
I'm afraid the only way to implement it in a type-safe manner is as follows:
C is an interface, apply().
C1 implements C, and has fields of type R1, P1.
C2 implements C, and has fields of type R2, P2.
The caller builds either C1 or C2, passes it to M, and M calls c.apply().
Note how M doesn't even see points, only the checker interface C. That's because there is nothing common between P1 and P2 that anyone other than then C can use.

Object-Oriented Programming: How to properly design, implement, and name a method which involve object interactions?

Language doesn't matter, it is generic object-oriented question(take java/C# etc). Take a simple concept.
A Person has a Car. The Person can drive the Car. Car doesn't usually drive or wander around, right? ``
But, usually in codes, we see methods like myCarObject.Drive().
Now when a Person is introduced, and the Person drives the car:
======================= First Way =================================
class Car{
int odometer;void drive(){ odometer++; }
}
class Person{
void driveCar(Car c) { c.drive(); }
}
========================================================================
================================ Alternative Way =======================
public Car{
int odometer; // car doesn't do the driving, it's the person, so no drive()
}
public Person{
void driveCar(Car c) { c.odometer++; }
}
========================== and other ways....============================
===========================================================================
So, my question is clear: what is the best way to design/implement/name methods in similar cases?
It's a bit difficult to make simplified examples like that make any sense, but here is an attemt:
A Car class would generally contain methods for the things that the object can do by itself with the information that it has, for example:
public class Car {
private bool engineOn;
public int Speed { get; private set; }
public void Start() { engineOn = true; Speed = 0; }
public void Accelerate() { Speed++; }
public void Break() { if (Speed > 0) Speed--; }
public void Stop() { Speed = 0; engineOn = false; };
}
A Person class would would manage a car by controlling the things that the car itself is not aware of in its environment. Example:
public class Person {
public void Drive(Car car, int speedLimit) {
car.Start();
while (car.Speed < speedLimit) {
car.Accelerate();
}
while (car.Speed > 0) {
car.Break();
}
car.Stop();
}
}
There are of course many different variations of how you can use OO in each situation.
If you wish to express your logic in a way that closely resembles human language semantics, you'll want to invoke an action or function on an entity which is logically capable of carrying it out.
When behavior cannot be placed on an object (in the sense that it has state), you put it in a Service or Utility class, or some similar construct. Authenticate is a classic example of something that doesn't make much sense to invoke on a user, or on any other object. For this purpose, we create an AuthenticationProvider (or service, whichever you prefer).
In your scenario of a Person and a Car, it's one object invoking behavior on another. person.Drive(car) would therefore make the most sense.
If a Person owns a Car (and a Car is always owned by a Person), then person.Drive() might be the only thing you need to do. The Drive() method will have access to the properties of person, one of which is its car.
An important thing to note here is the concept of loose coupling. In more complex scenario's, you don't want to all sorts of cross-references within your model. But by using interfaces and abstractions you'll often find yourself putting methods on objects where they don't really belong from a real-world perspective. The trick is to be aware of, and utilize a language's features for achieving loose coupling and realistic semantics simultaneously.
Keeping in mind that in a real application you'll have the bootstrapping code tucked away elsewhere, here is an example of how that might look like in C#:
We start off by defining interfaces for the things that can transport (ITransporter), and the things that can be transported (ITransportable):
public interface ITransportable
{
void Transport(Transportation offset);
}
public interface ITransporter
{
void StartTransportation(ITransportable transportable);
void StopTransportation(ITransportable transportable);
}
Note the Transportation helper class which contains the information necessary to re-calculate the current location of an ITransportable after it has been transported for a certain period of time with a certain velocity and whatnot. A simple example:
public class Transportation
{
public double Velocity { get; set; }
public TimeSpan Duration { get; set; }
}
We then proceed to create our implementations for these. As you might have guessed, Person will derive from ITransportable and Car derives from ITransporter:
public class Person : ITransportable
{
public Tuple<double, double> Location { get; set; }
private ITransporter _transporter;
void ITransportable.Transport(Transportation offset)
{
// Set new location based on the offset passed in by the car
}
public void Drive<TCar>(TCar car) where TCar : ITransporter
{
car.StartTransportation(this);
_transporter = car;
}
public void StopDriving()
{
if (_transporter != null)
{
_transporter.StopTransportation(this);
}
}
}
Pay close attention to what I did there. I provided an explicit interface implementation on the Person class. What this means is that Transport can only be invoked when the person is actually referenced as an ITransportable - if you reference it as a Person, only the Drive and StopDriving methods are visible.
Now the Car:
public class Car : ITransporter
{
public double MaxVelocity { get; set; }
public double Acceleration { get; set; }
public string FuelType { get; set; }
private Dictionary<ITransportable, DateTime> _transportations = new Dictionary<ITransportable, DateTime>();
void ITransporter.StartTransportation(ITransportable transportable)
{
_transportations.Add(transportable, DateTime.UtcNow);
}
void ITransporter.StopTransportation(ITransportable transportable)
{
if (_transportations.ContainsKey(transportable))
{
DateTime startTime = _transportations[transportable];
TimeSpan duration = DateTime.UtcNow - startTime;
var offset = new Transportation
{
Duration = duration,
Velocity = Math.Max((Acceleration*duration.Seconds), MaxVelocity)/2
};
transportable.Transport(offset);
_transportations.Remove(transportable);
}
}
}
Following the guidelines we set earlier, a Car will not have any (visible) methods on it, either. Unless you explicitly reference it as an ITransporter, which is exactly what happens inside of the Person's Drive and StopDriving methods.
So a Car here is just a Car. It has some properties, just like a real car, based on which you can determine a location offset after a person drove it for a certain amount of time. A Car cannot "Drive", "Start", or anything like that. A Person does that to a Car - a Car does not do that to itself.
To make it more realistic you would have to add all sorts of additional metadata that affect a Car's average velocity over a certain period of time on a certain route. Truth is, you probably won't end up modeling something like this anyway. I stuck with your model just to illustrate how you could retain natural language semantics if you were working with objects that make it challenging to do so.
An example of how these classes may be used by a client:
Person person = new Person();
Car car = new Car();
// car.Transport(); will not compile unless we explicitly
// cast it to an ITransporter first.
// The only thing we can do to set things in motion (no pun intended)
// is invoke person.Drive(car);
person.Drive(car);
// some time passes..
person.StopDriving();
// currentLocation should now be updated because the Car
// passed a Transportation object to the Person with information
// about how quickly it moved and for how long.
var currentLocation = person.Location;
As I already eluded before, this is by no means a good implementation of this particular scenario. It should, however, illustrate the concept of how to solve your problem: to keep the logic of "transportation" inside of the "transporter", without the need to expose that logic through public methods. This gives you natural language semantics in your client code while retaining proper separation of concerns.
Sometimes you just need to be creative with the tools you have.
In second case, it's like you're saying that the task of driving a car consist in incrementing the odometer. It's clearly not the driver's business, and a violation of encapsulation. The odometer should probably be an implementation detail.
In first case, the car maybe does not drive itself, but it advances, so you could use another verb. But car.advance() is maybe not how a Person drives cars... Even if it was thru vocal commands, the decoding of the command would probably result in a sequence of more basic commands.
I very much like the answer of Guffa which tries to address what driving a car could mean. But of course, you may have another context...

Design and encapsulation: Dictionary with multiple class instances, or one instance with many internal dictionaries

I have a Calculator class which takes data of n types, and returns a value based on some calculation on the data. I am generating the data in my Main class, and I'm faced with two options on how to design the Calculator class.
First option:
public class Main
{
Dictionary<DataType, Calculator> dataTypeToCalculator = new Dictionary<DataType, Calculator>()
void RecordResult(Data data)
{
Calculator calculator = dataTypeToCalculator[data.DataType]; //assume this exists
int result = calculator.Calculate(data);
StoreResult(result); //pretend this is implemented, it stores the result somewhere in Main object
}
}
public class Calculator
{
int field1 = 1;
int field2 = 2;
int Calculate(Data data)
{
return data.Value + field1 + field2;
}
}
Second option:
public class Main
{
Calculator calculator = new Calculator();
void RecordResult(Data data)
{
calculator.Calculate(data);
}
}
public class Calculator
{
Dictionary<DataType, int> dataTypeToField1 = new Dictionary<DataType, int>();
Dictionary<DataType, int> dataTypeToField2 = new Dictionary<DataType, int>();
void Calculate(Data data)
{
int field1 = dataTypeToField1[data.DataType];
int field2 = dataTypeToField2[data.DataType];
return data.Value + field1 + field2;
}
}
I have a couple of clean classes that don't have any internal fields where I can have one instance and just pass Data to it from the Main class and have it handle the different DataTypes. However, I have other classes with multiple necessary fields, and creating an internal dictionary for each one seems bad. Is there a standard "best practice" for this type of situation? In this example, I want the Calculator to encapsulate all of the calculating tasks, and not have to rely on the Main class to separate the data. However, this just doesn't seem right to me when my class has many fields.
Your case is really specific one, so I suppose there is no any "best practice" that fits your problem. Fortunately, there are general principles with my favorite one Single Responsibility Principle (SRP) from SOLID principles.
If I correctly understood your case, you have:
Calculator responsible for doing computations
Factory responsible for creation of Calculator instances
Configuration that contains data for Calculators
Repository responsible for data persistence
So I suggest creating separate classes responsible for specific functionalities: Calculator, CalculatorFactory, CalulatorConfiguration, CalculationResultsRepository, ...
Create a classes with more than one responsibility usually leads to the code which is difficult to manage, test and future development.

Populating association properties in entities from service call

Say I have a common pattern with a Customer object and a SalesOrder object. I have corresponding SalesOrderContract and CustomerContract objects that are similar, flatter objects used to serialize through a web service
public class Customer
{
public int CustomerId { get; set; }
public string Name { get; set; }
public Address ShippingAddress { get; set; }
//more fields...
}
public class Order
{
public int OrderId { get; set; }
public Customer Customer { get; set;
// etc
}
And my sales order contract looks like this
public class OrderContract
{
public int OrderId { get; set; }
public int CustomerId { get; set; }
}
public class OrderTranslator
{
public static Order ToOrder(OrderContract contract)
{
return new Order { OrderId = contract.OrderId };
// just translate customer id or populate entire Customer object
}
}
I have a layer inbetween the service layer and business object layer that translates between the two. My question is this...do I populate the Order.Customer object on the other end since the Order table just needs the customer id. I don't carry the entire customer object in the OrderContract because it's not necessary and too heavy. But, as part of saving it, I have to validate that it's indeed a valid customer. I can do a few things
Populate the Order.Customer object completely based on the CustomerId when I translate between contract and entity.. This would require calling the CustomerRepository in a helper class that translates between entities and contracts. Doesn't feel right to me. Translator should really just be data mapping.
Create a domain service for each group of operations that performs the validation needed without populating the Order.Customer. This service would pull the Customer object based on Order.CustomerId and check to see if it's valid. Not sure on this because a sales order should be able to validate itself, but it's also not explicitly dealing with Orders as it also deals with Customers so maybe a domain service?
Create a seperate property Order.CustomerId and lazy load the customer object based on this.
Populate Order.Customer in from a factory class. Right now my factory classes are just for loading from database. I'm not really loading from datacontracts, but maybe it makes sense?
So the question is two part...if you have association properties in your enties that will be required to tell if something is completely valid before saving, do you just populate them? If you do, where you do actually do that because the contract/entity translator feels wrong?
The bottom line is that I need to be able to do something like
if (order.Customer == null || !order.Customer.IsActive)
{
//do something
}
The question is where does it make sense to do this? In reality my Order object has a lot of child entities required for validation and I don't want things to become bloated. This is why I'm considering making domain services to encapsulate validation since it's such a huge operation in my particular case (several hundred weird rules). But I also don't want to remove all logic making my objects just properties. Finding the balance is tough.
Hope that makes sense. If more background is required, let me know.
You have a couple of things going on here. I think part of the issue is mainly how you appear to have arranged your Translator class. Remember, for an entity, the whole concept is based on instance identity. So a Translator for an entity should not return a new object, it should return the correct instance of the object. That typically means you have to supply it with that instance in the first place.
It is perhaps useful to think in terms of updates vs creating a new object.
For an update the way I would structure this operation is as follows: I would have the web service that the application calls to get and return the contract objects. This web service calls both repositories and Translators to do it's work. The validation stays on the domain object.
In code an update would look something like the following.
Web Service:
[WebService]
public class OrderService
{
[WebMethod]
public void UpdateOrder(OrderContract orderContract)
{
OrderRepository orderRepository = new OrderRepository(_session);
// The key point here is we get the actual order itself
// and so Customer and all other objects are already either populated
// or available for lazy loading.
Order order = orderRepository.GetOrderByOrderContract(orderContract);
// The translator uses the OrderContract to update attribute fields on
// the actual Order instance we need.
OrderTranslator.OrderContractToOrder(ref order, orderContract);
// We now have the specific order instance with any properties updated
// so we can validate and then persist.
if (order.Validate())
{
orderRepository.Update(order);
}
else
{
// Whatever
}
}
}
Translator:
public static class OrderTranslator
{
public static void OrderContractToOrder(ref Order order, OrderContract orderContract)
{
// Here we update properties on the actual order instance passed in
// instead of creating a new Order instance.
order.SetSomeProperty(orderContract.SomeProperty);
// ... etc.
}
}
The key concept here is because we have an entity, we are getting the actual Order, the instance of the entity, and then using the translator to update attributes instead of creating a new Order instance. Because we are getting the original Order, not creating a new instance, presumably we can have all the associations either populated or populated by lazy load. We do not have to recreate any associations from an OrderContract so the issue goes away.
I think the other part of the issue may be your understanding of how a factory is designed. It is true that for entities a Factory may not set all the possible attributes - the method could become hopelessly complex if it did.
But what a factory is supposed to do is create all the associations for a new object so that the new object returned is in a valid state in terms of being a full and valid aggregate. Then the caller can set all the other various and sundry "simple" attributes.
Anytime you have a Factory you have to make decisions about what parameters to pass in. Maybe in this case the web service gets the actual Customer and passes it to the factory as a parameter. Or Maybe the web service passes in an Id and the factory is responsible for getting the actual Customer instance. It will vary by specific situation but in any case, however it gets the other objects required, a factory should return at minimum a fully populated object in terms of it's graph, i.e all relationships should be present and traversible.
In code a possible example of new Order creation might be:
[WebService]
public class OrderService
{
[WebMethod]
public void SaveNewOrder(OrderContract orderContract)
{
// Lets assume in this case our Factory has a list of all Customers
// so given an Id it can create the association.
Order order = OrderFactory.CreateNewOrder(orderContract.CustomerId);
// Once again we get the actual order itself, albeit it is new,
// and so Customer and all other objects are already either populated
// by the factory create method and/or are available for lazy loading.
// We can now use the same translator to update all simple attribute fields on
// the new Order instance.
OrderTranslator.OrderContractToOrder(ref order, orderContract);
// We now have the new order instance with all properties populated
// so we can validate and then persist.
if (order.Validate())
{
//Maybe you use a Repository - I use a unit of work but the concept is the same.
orderRepository.Save(order);
}
else
{
//Whatever
}
}
}
So, hope that helps?