OOP design

 

All principles

General Principles

 

  • KISS → Start simple, add complexity only when needed
  • DRY → Reduce duplication, simplify maintenance
  • YAGNI → Build for today, not hypothetical futures
  • Separation of Concerns → Enable independent testing and changes
  • Law of Demeter → Reduce coupling, hide internal structure

 

SOLID Principles

 

  • SRP → Keep classes focused on one responsibility
  • OCP → Support future requirements without modifying existing code
  • LSP → Prevent brittle hierarchies that break at runtime
  • ISP → Keep interfaces clean and focused
  • DIP → Keep code flexible and testable through abstraction

SOLID

1. Single: 

This states that there should never be more than one reason for a class to change. In other words, every class should have only one responsibility.

  • Maintainability: When classes have a single, well-defined responsibility, they're easier to understand and modify.
  • Testability: It's easier to write unit tests for classes with a single focus.
  • Flexibility: Changes to one responsibility don't affect unrelated parts of the system.

2.Open–closed principle

The open–closed principle (OCP) states that software entities should be open for extension, but closed for modification.
  • Extensibility: New features can be added without modifying existing code.
  • Stability: Reduces the risk of introducing bugs when making changes.
  • Flexibility: Adapts to changing requirements more easily.

3 Liskov substitution principle

The Liskov substitution principle (LSP) states that functions that use pointers or references to base classes must be able to use objects of derived classes without knowing it. See also design by contract.

4 Interface segregation principle

The interface segregation principle (ISP) states that clients should not be forced to depend upon interfaces that they do not use.

Importance:

  • Decoupling: Reduces dependencies between classes, making the code more modular and maintainable.
  • Flexibility: Allows for more targeted implementations of interfaces.
  • Avoids unnecessary dependencies: Clients don't have to depend on methods they don't use.

5 Dependency inversion principle

The dependency inversion principle (DIP) states to depend upon abstractions, not concretes.

Importance:

  • Loose coupling: Reduces dependencies between modules, making the code more flexible and easier to test.
  • Flexibility: Enables changes to implementations without affecting clients.
  • Maintainability: Makes code easier to understand and modify.

SOLID原则的好处

  1. 易于维护 - 修改一个功能不影响其他部分

  2. 易于测试 - 可以单独测试每个模块

  3. 易于扩展 - 添加新功能只需添加新类

  4. 减少耦合 - 模块之间依赖最小化

  5. 提高复用 - 小模块可以在多个地方使用

SOLID原则不是必须严格遵循的规则,而是指导我们创建更灵活、可维护软件的设计指南。

 

Delivery Framework

1 Requirements (~5 minutes)

  • Primary capabilities — What operations must this system support?

  • Rules and completion — What conditions define success, failure, or when the system stops or transitions state?

  • Error handling — How should the system respond when inputs or actions are invalid?

  • Scope boundaries — What areas are in scope (core logic, business rules) and what areas are explicitly out (UI, storage, networking, concurrency, extensibility)?

 

2 Entities and Relationships (~5 minutes)

Don't overthink this. A simple list of entities and a few arrows showing which objects own or use which others is more than enough.

1)  Identify Entities

Start by scanning your requirements and pulling out the meaningful nouns. These are the “things” that clearly need to exist in your system. The goal is to capture the pieces of state and behavior that matter, not to model every word in the prompt.
 
2) Define Relationships
After identifying the entities, think through how they interact. This is where you establish the system’s shape:
  • Which entity is the orchestrator — the one driving the main workflow?
  • Which entities own durable state?
  • How do they depend on each other? (has-a, uses, contains)
  • Where should specific rules logically live?
These decisions give you a clean mental model of responsibilities, making the next step, class design, much more straightforward.
 

3  Class Design (~10-15 minutes)

Once you’ve named your entities and sketched how they relate, the next step is to turn each one into an outline of an actual class. This includes what it stores and what it does.
You’ll now go entity by entity, working top-down. Start with the orchestrator (for Tic Tac Toe, this is the Game class), then move down to the supporting entities (Board, Player, etc.).
For each entity, you'll answer two questions:
  1. State - What does this class need to remember to enforce the requirements?
  2. Behavior - What does this class need to do, in terms of operations or queries?
If you stay disciplined about tying both state and behavior back to your requirements, you avoid guessing and you avoid bloat.
 
1) Deriving State from Requirements
Go back to your requirements list and, for each entity, ask:
  • Which parts of the requirements does this entity own?
  • What information does it need to keep in memory to satisfy those responsibilities?

2) Deriving Behavior from Requirements

Once state is clear, move on to behavior. For each class, ask what operations the outside world needs and which requirements those operations satisfy. You're aiming for a small, focused API where each method corresponds to a real action or question implied by the problem.

 

4 Implementation (~10 minutes)

Start with the happy path—the normal flow when everything goes right. This makes the method's purpose and structure clear before you get into edge cases.
  • Happy Path - Walk through the method in a linear way: what inputs it receives, the sequence of steps it performs, the internal calls it makes to other classes, and what it returns or how it changes state. You want your interviewer to see how the system actually moves.
  • Edge Cases - After the happy path, enumerate the failure modes: invalid inputs, illegal operations, out-of-range values, calls that violate the current system state—anything that must be rejected or handled gracefully. This is an important step to demonstrate that you're thinking like someone who writes production code, not just toy logic.
 

5 Extensibility (~5 minutes, if time and level allow)

 

General Software Design Principles

If you only remember three general software design principles from this guide, make it KISS, DRY, and YAGNI. Those three will carry you through most interviews.

1) KISS - Keep It Simple, Stupid: 

2) DRY - Don't Repeat Yourself: When you find yourself writing the same logic in multiple places, pull it into one place.

 

3) YAGNI - You Aren't Gonna Need It. This principle doesn't mean "never think ahead" - it means don't build ahead. Design with extension in mind, but only implement what's needed now.
 

Separation of Concerns

Different parts of your code should handle different responsibilities, and they shouldn't know about each other's internals.

 

Law of Demeter

If you see code like order.getCustomer().getAddress().getZipCode(), that's violating the Law of Demeter.
The problem with deep chaining is coupling. Your code now knows the internal structure of three different objects. If any of them change how they organize their data, your code breaks.
Method chaining itself is not the problem. Fluent interfaces like builder.setName("John").setAge(30).build() are fine because they return the same object type. The issue is specifically when chaining leaks internal structure by traversing through multiple different object types.
 
 

 

posted @ 2026-01-13 11:47  ylxn  阅读(5)  评论(0)    收藏  举报