Skip to product information
The Beauty of Design Patterns
The Beauty of Design Patterns
Description
Book Introduction
Googler's Code Quality Management Secrets Revealed

Googlers, who placed a high value on code quality, went so far as to request corrections to even the smallest period error in the comments attached to the code, and thanks to such strict code quality control, the maintenance cost of the project was greatly reduced.
This book, a compilation of such experiences, provides detailed instruction on how to write high-quality code across five aspects: object-oriented paradigms, design principles, coding rules, refactoring techniques, and design patterns, based on over 200 real-world project examples.
  • You can preview some of the book's contents.
    Preview

index
Translator's Preface xiii
Beta Reader Review xiv
Beginning xvi

CHAPTER 1 Overview 1

1.1 Why Learn Code Design 1
__1.1.1 Writing High-Quality Code 2 / 1.1.2 Handling Complex Code Development 2
__1.1.3 Basic Programmer Skills 4 / 1.1.4 Skills Required for Career Development 5
__1.1.5 Thinking 5
1.2 Code Quality Assessment Method 6
__1.2.1 Maintainability 8 / 1.2.2 Readability 9 / 1.2.3 Extensibility 10 / 1.2.4 Flexibility 10
__1.2.5 Conciseness 11 / 1.2.6 Reusability 11 / 1.2.7 Testability 12 / 1.2.8 Thinking 12
1.3 How to Write High-Quality Code 12
__1.3.1 Object-oriented 13 / 1.3.2 Design principles 13 / 1.3.3 Design patterns 14
__1.3.4 Coding Rules 15 / 1.3.5 Refactoring Techniques 15 / 1.3.6 Thinking 17
1.4 How to Avoid Overdesign 18
__1.4.1 The original intention of code design is to improve code quality 18
__1.4.2 The principle of code design is that there is a problem in front and a solution behind it 18
__1.4.3 Application scenarios of code design should be applied to complex codes 19
__1.4.4 Continuous refactoring can effectively prevent overdesign 20
__1.4.5 Do not discuss code design outside of specific scenarios 20
__1.4.6 Thinking 21

CHAPTER 2 Object-Oriented Programming Paradigm 23

2.1 What is object-oriented programming? 23
__2.1.1 Object-Oriented Programming and Object-Oriented Programming Languages ​​23
__2.1.2 Object-oriented programming languages ​​that are not strictly defined 25
__2.1.3 Object-Oriented Analysis and Object-Oriented Design 26
__2.1.4 Notes on UML 27
__2.1.5 Thinking 28
2.2 Why Encapsulation, Abstraction, Inheritance, and Polymorphism Emerge 28
__2.2.1 Encapsulation 28 / 2.2.2 Abstraction 31 / 2.2.3 Inheritance 33 /
__2.2.4 Polymorphism 35 / 2.2.5 Reflections 39
2.3 How to Perform Object-Oriented Analysis, Object-Oriented Design, and Object-Oriented Programming 40
__2.3.1 Example Introduction and Difficulty Analysis 40
__2.3.2 How to Perform Object-Oriented Analysis 41
__2.3.3 Object-Oriented Design Methods 45
__2.3.4 How to do object-oriented programming 53
__2.3.5 Thinking 55
2.4 Differences Between Object-Oriented Programming, Procedural Programming, and Functional Programming 55
__2.4.1 Procedural Programming 55
__2.4.2 Comparison of Object-Oriented Programming and Procedural Programming 59
__2.4.3 Functional Programming 62
__2.4.4 Comparison of Object-Oriented Programming and Functional Programming 69
__2.4.5 Thinking 69
2.5 It looks like object-oriented programming, but it's actually procedural programming 70
__2.5.1 Abuse of getter and setter methods 70
__2.5.2 Abuse of global variables and global methods 74
__2.5.3 Defining a class by separating data and methods 77
__2.5.4 Thinking 79
2.6 Does the traditional development approach based on a poor domain model violate OOP? 79
__2.6.1 Traditional Development Methods Based on a Poor Domain Model 80
__2.6.2 DDD Development Method Based on Rich Domain Model 82
__2.6.3 Comparison of Two Development Methods 83
__2.6.4 Why Traditional Development Methods Based on Poor Domain Models Are So Widely Used 90
__2.6.5 Application Scenario 91 of DDD Development Based on Rich Domain Models
__2.6.6 Thinking 92
2.7 Abstract Classes and Interfaces 93
__2.7.1 Definition and Differences Between Abstract Classes and Interfaces 93
__2.7.2 Meaning of Abstract Classes and Interfaces 97
__2.7.3 Mock Implementations of Abstract Classes and Interfaces 100
__2.7.4 Application Scenarios of Abstract Classes and Interfaces 102
__2.7.5 Thinking 102
2.8 Interface-based programming:
Should I define an interface for every class? 102
__2.8.1 Various Ways to Understand Interfaces 103
__2.8.2 Let's put the design philosophy into practice 104
__2.8.3 How can we prevent abuse of interfaces? 108
__2.8.4 Thinking 109
2.9 Synthesis over Inheritance 109
__2.9.1 Why Inheritance is Deprecated 109
__2.9.2 Advantages of Composition over Inheritance 112
__2.9.3 Deciding Whether to Use Composition or Inheritance 114
__2.9.4 Thinking 115

CHAPTER 3 DESIGN PRINCIPLES 117

3.1 Single Responsibility Principle 117
__3.1.1 Definition and Interpretation of the Single Responsibility Principle 117
__3.1.2 How to determine if a class has a single responsibility 118
__3.1.3 Whether the class's responsibilities are described in as much detail as possible 121
__3.1.4 Thinking 123
3.2 Open-Closed Principle 123
__3.2.1 Open when extending, closed when modifying 123
__3.2.2 Does modifying code violate the Open Closed Principle? 129
__3.2.3 How to achieve openness when extending and closure when modifying 131
__3.2.4 How to flexibly apply the open-closed principle to a project 133
__3.2.5 Thinking 134
3.3 Liskov Substitution Principle 134
__3.3.1 Definition of the Liskov Substitution Principle 134
__3.3.2 Differences between the Liskov Substitution Principle and Polymorphism 136
__3.3.3 Anti-patterns that Violate the Liskov Substitution Principle 137
__3.3.4 Thinking 139
3.4 Interface Segregation Principle 139
__3.4.1 Interface as a set of APIs or functions 139
__3.4.2 Interfaces as a Single API or Function 141
__3.4.3 Interfaces in Object-Oriented Programming 142
__3.4.4 Thinking 149
3.5 Dependency Inversion Principle 149
__3.5.1 Inversion of Control 150 / 3.5.2 Dependency Injection 152 / 3.5.3 Dependency Injection Framework 153
__3.5.4 Dependency Inversion Principle 154 / 3.5.5 Reflection 155
3.6 The KISS Principle and the YAGNI Principle 155
__3.6.1 Definition and Interpretation of the KISS Principle 155
__3.6.2 Fewer lines of code are not simpler 156
__3.6.3 Complex code does not necessarily violate the KISS principle 158
__3.6.4 How to write code that satisfies the KISS principle 160
__3.6.5 Differences between the YAGNI and KISS Principles 160
__3.6.6 Thinking 161
3.7 DRY Principle 161
__3.7.1 Duplication of Code Logic 161 / 3.7.2 Functional (Semantic) Duplication 164
__3.7.3 Duplication of Code Execution 165 / 3.7.4 Code Reusability 167
__3.7.5 Thinking 169
3.8 LoD 169
__3.8.1 Thoughts on High Cohesion and Low Coupling 169
__3.8.2 Definition of LoD 171
__3.8.3 Definition Interpretation and First Example Code 171
__3.8.4 Definition Interpretation and Second Example Code 174
__3.8.5 Thinking 177

CHAPTER 4 Coding Rules 179

4.1 Naming and Annotation 179
__4.1.1 Long and short names 179
__4.1.2 Simplifying Naming Using Contextual Information 180
__4.1.3 Naming Unification Using a Business Glossary 180
__4.1.4 Naming should be precise but abstract 181
__4.1.5 Things that must be included in comments 181
__4.1.6 More Comments Isn't a Good Thing 183
__4.1.7 Thinking 183
4.2 Code Style 184
__4.2.1 Appropriate size of classes and functions 184
__4.2.2 Appropriate length of a line 185
__4.2.3 Separating code blocks using blank lines 185
__4.2.4 Indent 4 spaces or Indent 2 spaces 185
__4.2.5 Where should the opening brace be placed? 186
__4.2.6 Class Member Order 186
__4.2.7 Thinking 187
4.3 Coding Tips 187
__4.3.1 Modularizing Complex Code 187 / 4.3.2 Managing Function Parameters 188
__4.3.3 Removing flag parameters from functions 189 / 4.3.4 Removing deeply nested code 191
__4.3.5 Explanatory Variables 194 / 4.3.6 Reflections 195

CHAPTER 5 Refactoring Techniques 197

5.1 The Four Elements of Refactoring: Purpose, Target, Timing, and Method 197
__5.1.1 Purpose of Refactoring 197 / 5.1.2 Target of Refactoring 199
__5.1.3 When to Refactor 199 / 5.1.4 How to Refactor 200
__5.1.5 Thinking 201
5.2 Unit Testing 201
__5.2.1 About Unit Tests 201
__5.2.2 Why Write Unit Test Code 204
__5.2.3 How to Design Unit Tests 206
__5.2.4 Why Unit Tests Are Difficult to Write 209
__5.2.5 Thinking 210
5.3 Code Testability 210
__5.3.1 How to Write Testable Code 210
__5.3.2 Untestable Code 220
__5.3.3 Thinking 222
5.4 Decoupling 223
__5.4.1 Why Decoupling Is Important 223
__5.4.2 Determining Whether Code Needs Decoupling 223
__5.4.3 Code Decoupling Method 224
__5.4.4 Thinking 227
5.5 Refactoring Example 227
__5.5.1 Requirements and Development Background of the ID Generator 228
__5.5.2 Usable Level Code Implementation 228
__5.5.3 How to Find Code Quality Issues 230
__5.5.4 Refactoring for Readability 232
__5.5.5 Refactoring to Improve Code Testability 234
__5.5.6 Refactoring for Writing Unit Test Code 236
__5.5.7 Refactoring for Exception Handling 239
__5.5.8 Thinking 251

CHAPTER 6: GENERATIONAL DESIGN PATTERNS 253

6.1 Singleton Pattern (1) 253
__6.1.1 Definition of the Singleton Pattern 253 / 6.1.2 Implementation of the Singleton Pattern 254
__6.1.3 Application of the Singleton Pattern 259 / 6.1.4 Disadvantages of the Singleton Pattern 263
__6.1.5 Alternatives to the Singleton Pattern 266 / 6.1.6 Reflections 268
6.2 Singleton Pattern (2) 268
__6.2.1 Uniqueness of the Singleton Pattern 268
__6.2.2 Thread-Only Singleton Pattern 269
__6.2.3 Singleton Pattern in a Cluster Environment 270
__6.2.4 Multi-Instance Pattern 272
__6.2.5 Thinking 273
6.3 Factory Pattern (1) 273
__6.3.1 Simple Factory Pattern 274 / 6.3.2 Factory Method Pattern 278
__6.3.3 Abstract Factory Pattern 281 / 6.3.4 Application of Factory Pattern 283
__6.3.5 Thinking 283
6.4 Factory Pattern (2) 284
__6.4.1 Differences between DI Container and Factory Pattern 284
__6.4.2 Core Features of the DI Container 284
__6.4.3 Design and Implementation of the DI Container 287
__6.4.4 Thinking 292
6.5 Builder Pattern 293
__6.5.1 Creating Objects Using Constructors 293
__6.5.2 Setting member variables using setter methods 295
__6.5.3 Parameter Validation Using the Builder Pattern 296
__6.5.4 Applying the Builder Pattern in Guava 299
__6.5.5 Differences between the Builder Pattern and the Factory Pattern 301
__6.5.6 Thinking 301
6.6 Prototype Pattern 302
__6.6.1 Definition of the Prototype Pattern 302
__6.6.2 Applying the Prototype Pattern 302
__6.6.3 Implementing the Prototype Pattern 306
__6.6.4 Thinking 310

CHAPTER 7 Structural Design Patterns 313

7.1 Proxy Pattern 313
__7.1.1 Interface-Based Proxy Pattern 313
__7.1.2 Inheritance-based proxy pattern 316
__7.1.3 Reflection-Based Dynamic Proxy 317
__7.1.4 How to Use the Proxy Pattern 318
__7.1.5 Thinking 320
7.2 Decorator Pattern: Analyzing the Basic Design Thoughts of the Java IO Library 320
__7.2.1 Unusual Uses of the Java IO Library 320
__7.2.2 Inheritance-based design 322
__7.2.3 Design Planning Based on the Decorator Pattern 323
__7.2.4 Thinking 328
7.3 Adapter Pattern 328
__7.3.1 Class Adapters and Object Adapters 328
__7.3.2 Application of the Adapter Pattern 330
__7.3.3 Java Logging and the Adapter Pattern 336
__7.3.4 Wrapper Pattern 338
__7.3.5 Thinking 342
7.4 Bridge Pattern 343
__7.4.1 Definition of the Bridge Pattern 343
__7.4.2 Solving Explosive Inheritance with the Bridge Pattern 343
__7.4.3 Thinking 344
7.5 Facade Pattern 344
__7.5.1 Facade Pattern and Interface Design 345
__7.5.2 Applying the Facade Pattern: Improving Interface Usability 346
__7.5.3 Applying the Facade Pattern: Improving Interface Performance 346
__7.5.4 Applying the Facade Pattern: Solving Transaction Problems 346
__7.5.5 Thinking 348
7.6 Complex Pattern 348
__7.6.1 Directory tree based on composite pattern 348
__7.6.2 Human Tree Based on Complex Patterns 353
__7.6.3 Thinking 356
7.7 Flyweight Pattern 356
__7.7.1 Applying Flyweight Patterns in Chess Games 356
__7.7.2 Applying the Flyweight Pattern in a Text Editor 359
__7.7.3 Applying the Flyweight Pattern to Java's Integer 362
__7.7.4 Applying the Flyweight Pattern to Java's String 367
__7.7.5 Differences between the Flyweight Pattern, Singleton Pattern, Cache, and Object Pool 368
__7.7.6 Thinking 369

CHAPTER 8: BEHAVIORAL DESIGN PATTERNS 371

8.1 Observer Pattern 371
__8.1.1 Definition of the Observer Pattern 371
__8.1.2 Code Implementation of the Observer Pattern 372
__8.1.3 Meaning of the Observer Pattern 373
__8.1.4 Applying the Observer Pattern 376
__8.1.5 Asynchronous Non-Blocking Observer Pattern 377
__8.1.6 EventBus Framework 379
__8.1.7 Implementing the EventBus Framework from Scratch 382
__8.1.8 Thinking 388
8.2 Template Method Pattern (1) 388
__8.2.1 Definition and Implementation of the Template Method Pattern 388
__8.2.2 The Role of the Template Method Pattern: Reuse 390
__8.2.3 The Role of the Template Method Pattern: Extension 392
__8.2.4 Thinking 395
8.3 Template Method Pattern (2) 396
__8.3.1 Callback Principles and Implementation 396
__8.3.2 JdbcTemplate Class 398
__8.3.3 setClickListener() method 401
__8.3.4 addShutdownHook() method 402
__8.3.5 Differences between template method patterns and callbacks 404
__8.3.6 Thinking 405
8.4 Strategy Patterns 405
__8.4.1 Defining and Implementing the Strategy Pattern 405
__8.4.2 Replacing Branching Decisions with Strategy Patterns 408
__8.4.3 Sorting File Contents Using Strategy Patterns 410
__8.4.4 Misuse of the Strategy Pattern 417
__8.4.5 Thinking 417
8.5 Chain of Responsibility Pattern 417
__8.5.1 Defining and Implementing the Chain of Responsibility Pattern 417
__8.5.2 Sensitive Word Filtering Based on Responsibility Chain Pattern 423
__8.5.3 Servlet Filter Based on Chain of Responsibility Pattern 426
__8.5.4 Chain of Responsibility Pattern and Spring's Interceptors 430
__8.5.5 Chain of Responsibility Pattern and MyBatis Plugins 432
__8.5.6 Thinking 439
8.6 State Pattern 439
__8.6.1 What is a Finite State Machine? 439
__8.6.2 Implementing a State Machine Using Branching Decision Methods 442
__8.6.3 Implementing a State Machine Using Table Lookup Method 443
__8.6.4 Implementing a State Machine with the State Pattern 446
__8.6.5 Thinking 451
8.7 Iterator Pattern (1) 451
__8.7.1 Definition and Implementation of the Iterator Pattern 451
__8.7.2 Collection Iteration Method 454
__8.7.3 Iterator Problem 456
__8.7.4 Solving the Iterator Problem 458
__8.7.5 Thinking 463
8.8 Iterator Pattern (2) 464
__8.8.1 Iterator supporting snapshot functionality 464
__8.8.2 Design Thoughts Based on Multiple Copies 466
__8.8.3 Time-Based Design Thoughts 466
__8.8.4 Thinking 470
8.9 Visitor Pattern 470
__8.9.1 Derivation Process of the Visitor Pattern 470
__8.9.2 Double Dispatch 481
__8.9.3 Thinking 484
8.10 Memento Pattern 485
__8.10.1 Definition and Implementation of the Memento Pattern 485
__8.10.2 Time and Space Optimization 489
__8.10.3 Thinking 490
8.11 Command Pattern 490
__8.11.1 Definition of the Command Pattern 490
__8.11.2 Applying Command Patterns to Mobile Game Servers 491
__8.11.3 Differences between Command and Strategy Patterns 494
__8.11.4 Thinking 494
8.12 Interpreter Pattern 494
__8.12.1 Definition of the Interpreter Pattern 494
__8.12.2 Evaluating Expressions with the Interpreter Pattern 495
__8.12.3 Developing a Rules Engine with the Interpreter Pattern 499
__8.12.4 Thinking 502
8.13 Arbitrator Pattern 502
__8.13.1 Definition and Implementation of the Mediator Pattern 503
__8.13.2 Differences between the Mediator Pattern and the Observer Pattern 504
__8.13.3 Thinking 505

Search 506

Detailed image
Detailed Image 1

Into the book
We often say that we should pay attention to code quality and not neglect the code design phase before writing the code.
Underdesigning your code is not good, but overdesigning it is not good either.
In my past work experience, I've had many colleagues, especially engineers with little development experience, who liked to over-engineer their code and abuse design patterns.
They spend a lot of time designing their code before they even start coding.
For simple requirements or simple code, it is common to apply various design patterns during the development process in the hope that the code will be more flexible and serve as a solid foundation for future expansion.
However, over-designing only increases the complexity of the code, as requirements may not change later.
Therefore, we need to talk about how to avoid overdesign, especially how to avoid overusing design patterns, such as object-oriented programming paradigms, design principles, coding conventions, and refactoring.

--- p.18

However, most programmers often start writing code right after completing object-oriented analysis and object-oriented design in their head or in simple sketches, and they often optimize and refactor the code while writing it.
Conversely, even if you spend a lot of time on object-oriented analysis and design and draw solid class diagrams and UML diagrams before writing any code, it's impossible to define all the details and interactions at once.
As you write code, you still have to turn it around, refactor it, and repeat.
Ultimately, software development is essentially a process of continuous iteration, patching, problem finding, problem solving, and continuous refactoring.
It is important to understand that it is impossible to strictly complete one step and then move on to the next.

--- p.55

There is a more understandable way to explain the Liskov principle: design by contract.
When designing a subclass, it must follow the behavioral rules of the superclass.
The superclass defines the behavior rules of the function, and the subclass can change the internal implementation logic of the function, but cannot change the original behavior rules of the function.
The behavioral rules discussed here include what the function declares to implement, rules for input, output, exceptions, and any special case descriptions listed in the comments.
In fact, the relationship between superclass and subclass mentioned here could be replaced by the relationship between interface and implementation class.

--- p.137

The factory pattern is used to create objects of different but related types, such as a group of subclasses that inherit the same superclass or interface, where the type of object to be created is determined by pre-specified parameters.
On the other hand, the builder pattern creates objects of the same type with high complexity, but sets optional parameters or creates other objects through customization.
/ The difference between the two patterns can be easily understood through a classic example.
When a customer enters a restaurant and places an order, the factory pattern can be used to create a variety of foods such as pizza, burgers, and salads based on the customer's selection, and the builder pattern can be used to create a pizza with various toppings selected by the customer, such as cheese, tomatoes, and bacon.

--- p.301

When applying the Memento pattern, if the object to be backed up is relatively large or the backup frequency is high, the memory occupied by the snapshot will be relatively large, and the time required for backup and recovery will be relatively long.
How can we solve this problem? / Each application scenario has its own optimal solution.
For example, the example we looked at in Section 8.10.1 implemented undo functionality using the Memento pattern, but only supported sequential undo.
That is, when you undo, you can only undo the last text you entered, and you don't have to skip it and undo the previously entered text.
In this case, instead of storing the entire text in a snapshot to save memory, you can record only small amounts of information separately.
When you get the length of the text you entered when taking a snapshot, you can use a method to cut off that length from the original text.
--- p.489

Publisher's Review
Improve code quality with object-oriented programming, design principles, coding conventions, refactoring, and design patterns.

As developers gain experience, they become more driven by the desire to improve the quality of their code.
Unfortunately, however, many companies' development departments are in a rush to create each feature and meet the schedule.
If the code you wrote just works, there's no time or space to look at it again.
But when you maintain code that was hastily created like this, you get frustrated and want to delete all the code and rewrite it.

So how do you write high-quality code? Having worked in a development environment (Google) that significantly reduces maintenance costs through strict code quality control, the author recommends first acquiring theoretical knowledge of code design.
Knowledge of code design theory helps improve the maintainability, readability, extensibility, flexibility, conciseness, reusability, and testability of code.


Chapter 1 of the book defines what high-quality code is and shows you how to avoid overdesign.
Chapter 2 introduces object-oriented programming, which is the basis of design principles and design patterns, and Chapter 3 introduces important design principles such as the SOLID principle, KISS principle, YAGNI principle, DRY principle, and LoD principle.

In Chapter 4, you will learn coding conventions including naming, comments, code style, and coding tips. Chapter 5 covers the four elements of refactoring, unit testing, code testability, and decoupling, and you will learn refactoring techniques with examples.

Chapters 6, 7, and 8 introduce 22 design patterns, divided into three categories: creation, structure, and behavior.
Chapter 6 introduces creational design patterns, including the singleton pattern, factory pattern, builder pattern, and prototype pattern, and Chapter 7 introduces structural design patterns, including the proxy pattern, decorator pattern, adapter pattern, bridge pattern, facade pattern, composite pattern, and flyweight pattern.
Chapter 8 introduces behavioral design patterns, including the Observer Pattern, Template Method Pattern, Strategy Pattern, Chain of Responsibility Pattern, State Pattern, Iterator Pattern, Visitor Pattern, Memento Pattern, Command Pattern, Interpreter Pattern, and Mediator Pattern.

Although most of the code in this book is written in Java, the content and explanations are not language-specific and can be read by anyone using any programming language.
Recommended for all developers who want to improve their coding skills.
GOODS SPECIFICS
- Date of issue: May 26, 2023
- Page count, weight, size: 528 pages | 1,014g | 188*245*26mm
- ISBN13: 9791192987101
- ISBN10: 1192987101

You may also like

카테고리