MDE(Metadata-Driven Engine) is an application engine that aims at implementing Domain Driven Design principles to help developers pay more attention to Business Value. It's powered by MetaData Driven Design and Composite Oriental Programming to supports flexible and extensible architecture.
- COP as fundamental mechanism
- Interface as Metadata
- Composite is assembled at runtime
- Dynamic customization and extension supporting
- JDK 1.8+
please check Changes .
Core module is base layer of MDE that implemented the COP and provided plugin mechanism for extensions. In short, It's a dynamic code assembler using ByteBuddy.
- Path: core
- Features:
- Composite
- Mixin
- Property
- Behavior
- Extension
- Delegate
- Spring boot integration(core-spring)
Entity engine is a simple extension of Core module to support JDBI integration.
- Path: entity-engine
- Features:
- Entity
- Aggregate
- JdbiMixin
- Common Mixins
- Jdbi: SqlObject StringTemplate
- Spring boot integration(entity-engine-spring)
- Mustache template engine: JMustache
Event Engine implemented event bus based on Guava event-bus that supports sync or async application pub/sub mechanism.
- Path: event-engine
- Features:
- EventHandlerRoot
- EventHandler
- EventMixin
- SyncPost/AsyncPost
- Spring Boot integration(event-engine-spring)
FSM Engine extended standard Composite to FSM that support self-auto status transition according to events.
- Path: fsm-engine
- Features:
- FSM
- FsmAction
- FsmTransitionHandler
Composite in COP just likes Object in OOP. It's an implementation of Composition over inheritance principle. The Composite of MDE is assembled according to metadata that annotated with @Composite on the fly, and the definition of Composite is composed by Mixins that presents a code fragment.
In object-oriented programming languages, a Mixin is a class that contains methods for use by other classes without having to be the parent class of those other classes. How those other classes gain access to the mixin's methods depends on the language. Mixins are sometimes described as being "included" rather than "inherited".
Definition:
Mixins are a language concept that allows a programmer to inject some code into a class. Mixin programming is a style of software development, in which units of functionality are created in a class and then mixed in with other classes.
A mixin class acts as the parent class, containing the desired functionality. A subclass can then inherit or simply reuse this functionality, but not as a means of specialization. Typically, the mixin will export the desired functionality to a child class, without creating a rigid, single "is a" relationship. Here lies the important difference between the concepts of mixins and inheritance, in that the child class can still inherit all the features of the parent class, but, the semantics about the child "being a kind of" the parent need not be necessarily applied.
Advantages:
- It provides a mechanism for multiple inheritance by allowing multiple classes to use the common functionality, but without the complex semantics of multiple inheritance.
- Code reusability: Mixins are useful when a programmer wants to share functionality between different classes. Instead of repeating the same code over and over again, the common functionality can simply be grouped into a mixin and then inherited into each class that requires it.
- Mixins allow inheritance and use of only the desired features from the parent class, not necessarily all of the features from the parent class.
It’s a bit academic and not everyone agrees on these definitions, but it goes something like this:
- First off we have the interface. This is a protocol that just has method signatures but no actual code. This is what Objective-C and Swift 1.2 have.
- A trait also has the actual method bodies. In other words, a trait adds code to an interface. This is the new thing that Swift 2.0 lets us do today with protocol extensions.
- A mixin is like a trait but it also has state. We can’t really do this yet with Swift 2.0 as you’re not allowed to add stored properties to protocols.
It's Composition Oriented Programming. COP allows developers to work with 'fragments', smaller than classes, and 'compose' fragments into larger 'composites' which acts like the regular objects.
Composition over inheritance (or composite reuse principle) in object-oriented programming (OOP) is the principle that classes should achieve polymorphic behavior and code reuse by their composition (by containing instances of other classes that implement the desired functionality) rather than inheritance from a base or parent class.
An extension presents the customizations and extensions of target composite. The Composite Engine will enhance target composite according to extension definitions at runtime. The extension mechanism supports adding new properties/methods and override target's method by @Delegate(Warning: don't use append mode when the extension inheriting the delegate source).
// === OOP style ===
// Class is a template of Objects, it's the definition.
class Car {
String model;
int cyclinders;
int displacement;
int horsepower;
int torque;
int weight;
int length;
int width;
int height;
int speed;
void ignite() {
//...
}
void run() {
//...
}
}
class Suv extends Car {
float approachAngle;
float depatureAngle;
void offroad() {
//...
}
}
// === COP style ===
// Mixins definition.
@Mixin
interface ModelMixin {
@Property
String getModel();
void setModel(String model);
@Property
int getLength();
void setLength(int length);
@Property
int getWidth();
void setWidth();
@Property
int getHeight();
void setHeight();
}
@Mixin
interface EngineMixin {
@Property
int getCylinders();
void setCylinders(int cyclinders);
@Property
int getDisplacement();
void setDisplacement(int displacement);
@Property
int getHorsepower();
void setHorsepower(int horsepower);
default void ignite() {
//...
}
}
@Mixin
interface Runable {
@Property
int getSpeed();
void setSpeed(int speed);
default void run() {
//...
}
}
@Mixin
interface Offroadable {
@Property
float getApproachAngle();
void setApproachAngle(float approachAngle);
@Property
float getDepatureAngle();
void setDepatureAngle(float depatureAngle);
default void offroad() {
//...
}
}
@Mixin
interface Flyable {
@Property
int getX();
void setX(int x);
@Property
int getY();
void setY(int y);
@Property
int getZ();
void setZ(int z);
default viod fly() {
//...
}
}
//Composite definition
@Composite
interface Car extends ModelMixin, EngineMixin, Runnable {
}
@Composite
interface Suv extends ModelMixin, EngineMixin, Runnable, Offroadable {
}
//Extension definition
@Extension(target=Car.class)
interface FlyCar extends Car.class, Flyable {
@Delegate(name = "run", parameterTypes = {})
default void run(@Self Flyable self) {
self.fly();
}
}
Directly say, no way in JDK 8.0! But JDK 9.0 had been released now that has added "Private methods on interfaces" feature. Still, there're some tricks to help enclose members as private members:
//Naming methods start with '_' to indicate these are private and should not use outside of the composite.
//But properties are not suitable as methods, because properties should follow the java bean standard.
@Composite
interface Cat {
@Property
String getColor();
void setColor(String color);
default void _meow() {
System.out.println("meow...");
}
default void playWith(String butterfly) {
_meow();
//...
}
}
//Enclose private members in inner classes that only has private constructor methods.
@Composite
interface Cat {
@Property
Cask getCask();
void setCask(Cask cask);
@Initializer
default void preset() {
setCask(new Cask());
}
default void playWith(String butterfly) {
getCask().meow();
}
class Cask {
private String color;
//Change constructor scope to private to prevent createing outside of Cat.
private Cask(){
}
private void meow() {
System.out.println("meow...");
}
}
}