I'm building a control system for a hardware installation (water circulation system). I've designed it in two layers: the hardware description layer and the control layer.
+----------------------------------------------+
| Control (enables manipulation of devices) |
+----------------------------------------------+
| uses (decorates)
v
+---------------------------------------+ (de)serialize +------------+
| HW Description |<--------------->| Files / DB |
| (stores physical layout, cabling etc) | +------------+
+---------------------------------------+
The hardware description layer contains a map of the hardware, describing how pipes are connected to heat exchangers and other equipment. The data for this layer is configurable per installation, and will be read in at runtime. Therefore all the classes in the hardware description layer should be serializabl开发者_运维百科e in one way or another (via Hibernate / serialization to XML or so).
The control layer will decorate the hardware description layer classes with intelligence, so the heat exchanger will for instance get a HeatExchangerController associated with it.
In this system, the entities in the control layer might need to seek out their neirest neighbours via the hardware description, so the heat exchange controller might do something like
HeatExchangerController neighbour = this.getHeatExchanger().getInputPipe().getOtherSide().getHeatExchanger().getController();
neighbour.notify(highLoadAlert);
The problem is that this makes the lower layer (the hardware layer) aware of the intelligence above it (its controller(s)). Not only is this breaking the one-way dependency rule between the layers, but since all hardware description classes should be serializable this complicates the code, since all references to the higher layers need to be optional, declared transient etc.
Now I'm a bit stuck trying to decide if it is a good or bad idea to make the control available through the HW description layer like this, or if there are any alternative approaches to take. I can only think of one method which would involve mirroring and delegating almost all of the HW description layer, which seems way to intrusive to be good.
So my question is if any of you recognize this situation and have any tips / experiences. Does it have a name? Are there are any good patterns /best practices for it, and are there are any other well-known libraries / frameworks which also have had and worked around this situation?
Thank you.
You haven't shown us what benefit you get from seperating the controller logic from the hardware description. Are you sure this separation is worth the effort?
It sounds like you are building an Anemic Domain Model?
Take a domain driven approach.
If you break the system vertically (domains) as well. Then these vertical components can talk to each other via the controllers and nothing else. Keep the horizontal layers within each domain and the layering is vertical within a domain and each domain is isolated from each other inasmuch that they can can only communicate via the controllers.
not too sure what your problem is. if you don't want a getController() method in your hardware class, you can store hardware->controller mapping in a weak hash map
public class Controller
static WeakHashMap<Hardware,Controller> map = ...
static public Controller of(Hardware hw){ return map.get(hw); }
Controller(Hardware hw)
{
map.put(hw, this);
}
very often, people love to add "convenient" methods, having no fear of complexity in dependencies
user.getThis()
user.getThat()
user.getTheOthers()
while User
class is a core class, it shouldn't have knowlege of This, That and The Others. Now a lof ot code depend on User class, and the User class has dependency on a lot of other classes. The end result is every class in the application depends on every other class, a big ball of mess.
This is the complicated solution I had in mind. It adds a decoration layer on top of the HW layer, which adds the links up to the control layer to each HW object:
-+
+--------------------------+ +-----------------+ |
| HeatExchangerController | | PipeController | > Controller Layer
+--------------------------+ +-----------------+ |
^ 1 controller ^ 1 controller -+
| |
v 1 heatExchanger v 1 pipe -+
+---------------------------+ inputPipe 1 +------------------+ |
| ControlAwareHeatExchanger |--------------| ControlAwarePipe | > Decorated HW Layer
+---------------------------+ 1 otherSide +------------------+ |
| | -+
v 1 realExchanger v 1 realPipe -+
+---------------------------+ inputPipe 1 +------------+ |
| HeatExchanger |--------------| Pipe | > HW Layer
+---------------------------+ 1 otherSide +------------+ |
-+
The Decorated layer will contain code like:
class ControlAwareHeatExchanger {
private final HeatExchanger realExchanger;
private final ControlAwarepipe inputPipe;
public ControlAwareHeatExchanger(HeatExchanger decoratee) {
realExchanger = decoratee;
inputPipe = new ControlAwarePipe(decoratee.getInputPipe());
}
public ControlAwarePipe getInputPipe() {
return inputPipe;
}
...
}
This way you can do:
ControlAwareHeatExchanger controlHE = heatExchangerController.getHeatExchanger();
ControlAwarePipe controlInputPipe = controlHE.getInputPipe();
ControlAwareHeatExchanger otherHE = controlInputPipe.getOtherSide();
HeatExchangerController otherController = otherHE.getController();
So you can go down to the decorated hw layer, jump around, and then return to the controller layer again, all without the hw layer knowing about the control layer.
But as you can see, you need to mirror all connections and decorate the whole HW layer to acheive this. A lot of delegation will be involved. Thoughts?
精彩评论