The goal of modeling domain concepts through OOP object sets has not been fully realized for a long time. So so far, what are the fundamental problems that we have worked so hard to solve? Is there a better solution? In this article we'll introduce the concept of cop,composite oriented programming, show how it avoids some of the problems with OOP, and first ignite the hope of modeling with reusable parts assembly.
Problem
What am I for? In practice I can have multiple identities. At some point, I'm a developer of software, and at other times I'm explaining a software developer about Java topics. But other times, I may have a completely different identity, such as bank clients, university alumni. In short, my identity at different times was determined by the specific circumstances of the time. In different environments, I need to interact with the corresponding behavior through different interfaces. In all of these environments, I actually have a different interface to the same object. When I write the software, the bank doesn't appear to be another me.
Solution
If you model OOP for me in software, some people will design me as a developer class. But such a class obviously cannot express my different identities at different times (such as a college alumnus, because the developer class does not include social concepts). So the result of modeling for me might be a few different classes, or implement all the behaviors in a class. In this article, we propose another solution: to use the mixin (mixed) concept to complete this implementation.
Combination
First, Mixin is implemented as a common Java class, which typically implements a specific interface that will be part of the interface that composite is exposed to. Next, we declare a composite: Create a Java interface, declare the mixin it uses with annotations, and use the "extends" keyword to indicate which domain interfaces are exposed. By this method, we can set up a centralized location to clearly define the structure and behavior of composite.
While using COP, it is a good idea to keep crosscutting concerns in separate implementation classes, but their assembly or composition should be described in a centralized Java interface. To avoid duplicate descriptions, we can reuse the declarations in the extended interface through the "extends" keyword. In this way, if the extended interface is modified, the composite interface declaration from which it is extended will automatically change, without the need for us to make manual modifications individually.
In this way, we believe that we can do the best of both worlds: the concerns that exist in each individual implementation class are decoupled, each class only needs to focus on a specific task, and the description of what the composite should ultimately be is centralized and determined, Composite developers are solely responsible for what should be included in the definition.
code example
How does composite apply in practice? Let's look at an example. Suppose I am a composite, then I can describe myself as follows:
@Mixins({DeveloperMixin.class, SpeakerMixin.class, AlumniMixin.class})
public interface HumanComposite
extends Developer, Speaker, Alumni, Composite
{}
The extended interface contains the actual method to be invoked, and the QI4J runtime environment constructs a composite instance that routes "calls from the client" to a particular mixin instance. But from the client's point of view, this composite instance is entirely a normal Java object (although it has more interfaces than the domain object that the common Oop method implements). A domain interface such as developer is a generic interface, and qi4j has no special relationship with it, and its implementation itself is a simple Java class that implements the interface. But the identity of the domain object described above is defined by the composite instance rather than by a mixin instance, which resolves the identity problem: a reference to the object "I" can be passed through the system and passed on to interfaces that are useful in a particular context. If more domain or context environment is introduced, it can also be handled by extending this composite.
If you want to create another composite and its implementation that also uses the Alumni interface, we can have this interface extend alumni and declare that the same mixin is used. As a result, common problems with multiple inheritance and reuse base classes are also addressed.
LMM structure
Software is usually divided into modules, layered design on paper. We are already familiar with the following design drawings:
The diagram contains multiple modules, and different modules form different layers, and the layers are stacked together. We can refer to this design method simply as lmm (layered Modules metaphor, layered module notation). The LMM chart can be used to convey a general overview of the overall application, so that we don't get bogged down in too much detail. Designing systems in strict accordance with LMM requirements can reduce system defects and reduce long-term maintenance costs, and this system can reflect more flexibly on future changes. Most projects use LMM to describe how the application is constructed, and many projects try to follow lmm, but only a few projects do so. I think we've all seen a lot of painful lessons, like using the Web layer's classes directly in the classes in the infrastructure layer.