DA01 SOLID & Layering
Tags: course, design, architecture
Published: 2020-08-14 02:57:48

## 本篇主要讲了以下内容：

- Symptoms of Bad Design
- SOLID
- Layering
    - 表现层
    - 业务层
    - 数据层
- Transactions

# Symptoms of Bad Design

- Rigidity: The design is difficult to change. 
- Fragility: The design is easy to break.
- Immobility: The design is difficult to reuse. 可重用性差
- Viscosity: It is difficult to do the right thing.
- Needless complexity: The design contains elements that aren’t currently useful.
- Needless repetition: Redundant modules/code in the system makes it is difficult to maintain it.
- Opacity: The design has modules that are difficult to understand.

# SOLID

## Single Responsibility Principle

一个类只有一个职责

如果A类负责两个不同的职责：R1，R2。当由于R1需求发生改变而需要修改类A时，有可能会导致原本运行正常的R2功能发生故障。也就是说R1和R2被耦合在了一起。

在下面的Book类中，`printTextToConsole()`方法就违反了SRP，因为把书的内容打印到控制台不是Book的职责。
```java
public class Book {
    privateString name;
    privateString author;
    privateString text;

    // constructor, getters and setters

    // methods that directly relate to the book properties
    public String replaceWordInText(String word) {
        returntext.replaceAll(word, text);
    }

    public boolean isWordInText(String word) {
        returntext.contains(word);
    }

    // This method is not appropriate
    void printTextToConsole(){
        // our code for formatting and printing the text
    }
}
```
可以将`printTextToConsole()`方法交给BookPrinter类：
```java
public class BookPrinter {
    // methods for outputting text
    void printTextToConsole(String text) {
        // our code for formatting and printing the text
    }
    void printTextToAnotherStyle(String text) {
        // code for writing to any other location.
    }
}
```

## Open Closed Principle

类的行为对**扩展**是开放的，对**修改**是封闭的。即可扩展(extension)，不可修改(modification)。

对于Book类，如果想加一个新的feature：书中含有音乐，我们不应该在原有的Book类中加入新的music属性，而是创建一个新的类SuperBookWithMusic：
```java
public class SuperBookWithMusicextendsBook {
    private String music;
    //constructor, getters + setters

    public void playMusic() {
        // code for playing music
    }
}
```

## Liskov Substitution Principle

一个对象在其出现的任何地方，都可以用子类实例做替换，并且不会导致程序的错误。

下面的例子就违反了LSP，Project类的`start()`方法在执行时会抛出异常：
```java
public class Employee {
    public void work() {
        System.out.println("Employee is working");
    }
}
```

```java
public class EmployeeOnVacation extends Employee {
    @Override
    public void work() {
        throw new IllegalArgumentException("Employee is on vacation");
    }
}
```

```java
//imagine we assign our employees to start working on it
List<Employee> employees = new ArrayList<>();
employees.add(new EmployeeOnVacation());
employees.add(new Employee());
Project project= new Project();
project.start(employees);

//and that we have a project
public class Project {
    public void start(List<Employee> employees) {
        for(Employee employee:employees) {
            employee.work();
        }
    }
}
```

## Interface Segregation Principle

接口隔离原则表明客户端不应该被强迫实现一些他们不会使用的接口，应该把胖接口中的方法分组，然后用多个接口替代它，每个接口服务于一个子模块。大的接口应该分割成多个小的接口。

对于下面的例子，`TigerKeeper`中不应该有那么多的方法，因为现实中这些事情不是全都一个人在做。
```java
public interface TigerKeeper {
    void washTiger();
    void feedTiger();
    void petTiger();
}
```

正确的做法是将它分为多个接口：
```java
public class TigerCarer implements TigerCleaner, TigerFeeder {
    public void washTiger() {
        //Puppy day. Let’s not miss a spot!
    }
    public void feedTiger() {
        //TGIF: chicken time
    }
}
```

## Dependency Inversion Principle

**Dependency**: High-level modules should not depend on low-level modules. Both should depend on abstractions;

**Inversion**: Abstractions should not depend on details. Details should depend on abstractions.

开闭原则(OCP)是面向对象设计原则的基础也是整个设计的一个终极目标，而依赖倒置原则(DIP)则是实现OCP原则的一个基础，换句话说开闭原则(OCP)是你盖一栋大楼的设计蓝图，那么依赖倒置原则就是盖这栋大楼的一个钢构框架。

以下代码可以使用DIP进行优化：
```java
public class BackEndDeveloper {
    public void writeJava() {
    }
}

public class FrontEndDeveloper {
    public void writeJavascript() {
    }
}
```

使用`develop()`对前端后端程序员进行抽象化：
```java
public interface Developer {
    void develop();
}

public class BackEndDeveloper implements Developer {
    @Override
    public void develop() {
        writeJava();
    }
    private void writeJava() {
    }
}

public class FrontEndDeveloper implements Developer {
    @Override
    public void develop() {
        writeJavascript();
    }
    public void writeJavascript() {
    }
}
```

# Layering

分层是软件设计者用来分解复杂软件系统的最常见的技术之一。

Each layer depends on the layers below to fulfil responsibilities
- No knowledge of layers above
- Only knowledge of layer directly below

## 三种典型的Layer

- **Presentation** or UI layer: responsible for handling interactions between the user and the system;
- Business or **domain** layer: responsible for implementing the logic of the system
- **Data source** layer: databases, file systems, messaging systems, and external data sources.

## 优缺点

### Pros

- Understandability: 对于一层layer，要理解它只需理解该层以下的层即可；
- Substitution: 
- Re-usability: 

### Cons

- Change: 修改了下层需要对上层进行修改；
- Performance: 效率低。

# Transactions

So many enterprise systems are built around transactions. Transactions are the primary tool used for preventing conflicts in **concurrent access** of data.

## ACID properties

- Atomicity
- Consistency
- Isolation
- Durability

## Business transaction vs. System transaction

Business transaction就是我们常说的“交易”，而System transaction则是“事务”。可能在英语中这碰巧是一个词，容易混淆。