Boundaries are areas of integration between external code (tripartite packages, open source, components and subsystems built by other teams) and self-written code

1. Use third-party code

1. Third-party package and framework providers pursue universality so that they can work in multiple environments and appeal to a wide range of users.

2. We recommend not passing Map (or any other interface on the boundary) through the system, keeping it in a class or a close relative, and avoiding returning the boundary interface from the API or passing the interface as a parameter to the public API.

For example, an application might construct a Map object and pass it around. Our intention may be that none of the recipients of the map object delete anything in the map. But map happens to have a clear method.

Map<Sensor> sensors = new HashMap<Sensor>();
Sensor s = sensors.get(sensorId)
Copy the code

The unrestricted transfer of Map entities in the system means that when the Map interface is modified, there are many changes to follow.

A cleaner way to use Map is roughly as follows. Sensors users don’t care if generics are used, that will be implementation details

public class Sensor {
    private Map sensors = new HashMap();

    public Sensor getById(String id){
        return(Sensor) sensors.get(id); }}Copy the code

Again for instance

Simple scenario: Generate a Map object, set a key-value pair, and get it

const p = new Map();
p.set('name'.'yxfan');
p.get('name');

/ / code 2
class Person {
    constructor(){
        this.person = new Map();
    }
    set() {
        this.person.set('name'.'yxfan');
    }
    get() {
        return this.person.get('name'); }}const p = new Person();
p.set(a); p.get('name');
Copy the code

Consider: What is the difference between code 1 and Code 2? What are the benefits of code two?

  • The Map in code 1 provides too much room for manipulation
  • Code 2 hides rich interfaces and only preserves interfaces that meet specific requirements, thus avoiding misuse

2. Browse and learn boundaries

Where to start when leveraging third-party packages?????

  • It is not our responsibility to test third party code, but it may be in our best interest to write tests for the third party code to use.
  • Instead of experimenting with new things in production code, write tests to view and understand third-party code.

The article calls it the “learning test.” Learning tests are precision tests that help us improve our understanding of the API. When a new version of a third-party package is released, we can run learning tests to see if the behavior of the package changes and make sure the third-party package works the way we want it to.

Take Echart for example

const myChart = echarts.init(document.getElementById('echart-container'));
const option = {
    title: {
        text: 'Getting started with ECharts'
    },
    tooltip: {},
    legend: {
        data: ['sales']
    },
    xAxis: {
        data: ["Shirt"."Cardigan"."Chiffon shirt."."Pants"."High heels"."Socks"]
    },
    yAxis: {},
    series: [{
        name: 'sales',
        type: 'bar',
        data: [5.20.36.10.10.20]
    }]
}
myChart.setOption(option);
Copy the code

After writing this test, we will know how to use Echarts, including how to initialize and configure it, and then we can use this knowledge to encapsulate Echarts into our own class, so that its boundaries become what we want them to be.

class Echart {
    constructor(container) {
        this.myChart = echarts.init(container);
    }
    setOption(option) {
        this.myChart.setOption(option);
    }
    clear() {
        this.myChart.clear(); }}const myChart = new Echart(document.getElementById('echart-container'));
myChart.setOption(option);

Copy the code
  • Learn log4j
public class LogTest { 
    private Logger logger;

    @Before
    public void initialize(a) {
        logger = Logger.getLogger("logger"); 
        logger.removeAllAppenders();    
        Logger.getRootLogger().removeAllAppenders();
    }

    @Test
    public void basicLogger(a) {
        BasicConfigurator.configure();
        logger.info("basicLogger"); 
    }

    @Test
    public void addAppenderWithStream(a) {
        logger.addAppender(new ConsoleAppender( 
                             new PatternLayout("%p %t %m%n"), 
                             ConsoleAppender.SYSTEM_OUT));
        logger.info("addAppenderWithStream"); 
    }

    @Test
    public void addAppenderWithoutStream(a) {
        logger.addAppender(new ConsoleAppender(
                             new PatternLayout("%p %t %m%n")));
        logger.info("addAppenderWithoutStream"); }}Copy the code

After writing this test, we know how to use Log4J, including how to initialize and configure it, and then we can use what we’ve learned to package Log4j into our own class so that its boundaries look exactly as we want them to.

3. The benefits of learning tests go beyond being free

  • Learning tests are precision tests that help us improve our understanding of the API

  • When a new version of a third-party package is released, we can run a learning test to see if the package’s behavior changes

  • Learning tests ensure that third-party packages work the way we want them to. Once integrated, there is no guarantee that third-party code will always be compatible with our needs. If changes made to third-party packages are incompatible with the tests, we can spot them immediately

4. Use code that doesn’t exist yet

There’s another kind of boundary, the one that separates the known from the unknown. There are always places in the code that are beyond our knowledge. Sometimes we don’t look over the border

One of the benefits of writing the interface we want is that it’s under our control. This helps keep the client code more readable and focused on what it’s supposed to do.

Here I think the examples in the book are pretty good

5. Clean boundaries

  • 1. Changes on the boundary, with good software design, can be modified without huge investment and rewrite

  • 2. The code on the boundary needs to be clearly segmented and defined with the desired tests. It is better to depend on what you can control than to depend on what you can’t control so that you won’t be controlled later

  • 3. We can use ADAPTER mode to convert our interface to an interface provided by a third party


6. Adapter mode

The Adapter pattern, also known as the Adapter pattern, is one of the structural patterns through which you can change the interface form of existing classes (or external classes).

In large-scale system development, we often encounter situations such as: we need to implement some functionality, which already has one or more external components that are not mature enough to spend a lot of time redeveloping. So in many cases, external components will be used for the time being and replaced at any time later. The problem with this, however, is that with the replacement of an external component library, extensive changes may be required to the source code that references that external component, so new problems are likely to be introduced, and so on. How to minimize the modification surface?

The Adapter pattern was developed to address a similar need. The Adapter pattern transparently invokes external components by defining a new interface that abstracts the functionality to be implemented and an Adapter class that implements that interface.

When you replace external components in this way, you only need to modify a few Adapter classes at most, and the rest of the source code is unaffected.

(Inheritance)

public class Current {
    
    public void use220V(a) {
        System.out.println("Use 220V airwaves."); }}public class Adapter extends Current{
    public void use18V(a) {
        System.out.println("Use adapter");
        this.use220V(); }}Copy the code

(Way of delegation)

public class Adapter2 {
    private Current current;
    
    public Adapter2(Current current) {
        this.current = current;
    }
    
    public void use18V(a) {
        System.out.println("Use adapter");
        this.current.use220V(); }}Copy the code

The main function

public class MainClass {
    public static void main(String[] args) {
// Current current = new Current();
// current.use220V();
        
// Adapter adapter = new Adapter();
// adapter.use18V();
        
        Adapter2 adapter = new Adapter2(newCurrent()); adapter.use18V(); }}Copy the code

Advantages:

  • You can have any two unrelated classes run together.
  • 2. Improved class reuse.
  • 3. Increased class transparency.
  • 4. Good flexibility.

Disadvantages:

  • 1. Too much use of adapters will make the system very messy and difficult to grasp as a whole. For example, clearly see is called A interface, in fact, internal adaptation into the IMPLEMENTATION of THE B interface, A system if too much of this situation, is tantamount to A disaster. So if you don’t have to, you can skip the adapter and refactor your system directly.

  • 2. Since JAVA inherits at most one class, at most one adaptor class can be adapted, and the target class must be abstract.

Usage scenario: The adapter pattern should be considered when you are motivated to modify the interface of a functioning system.

Look at design patterns in detail


6. References

The way of clean code fanxiaopa. Top / 2021/01/11 /… Blog.csdn.net/ymybxx/arti…

Pay attention to the public account “Programmer interview”

Reply to “interview” to get interview package!!

This public account to share their own from programmer xiao Bai to experience spring recruitment autumn recruitment cut more than 10 offer interview written test experience, including [Java], [operating system], [computer network], [design mode], [data structure and algorithm], [Dacheng face by], [database] look forward to you join!!

1. Computer network —- Three times shake hands four times wave hands

2. Dream come true —– Project self-introduction

Here are the design patterns you asked for

4. Shocked! Check out this programmer interview manual!!

5. Teach you the interview “Profile” word for word

6. Nearly 30 interviews shared