详解设计模式之六大原则(补)
设计模式的六大原则是面向对象编程的核心思想,它们指导我们如何编写灵活、可维护和可扩展的代码。
1. 单一职责原则(Single Responsibility Principle, SRP)
定义:
一个类应该只有一个引起它变化的原因,或者说一个类只负责一项职责。
核心思想:
将功能分解到最小粒度,每个模块或类专注于完成某一个特定的任务。
示例:
PHP 示例:
// 不符合 SRP 的设计
class Report {
public function generateReport() {
echo "Generating report...\n";
}
public function saveToFile($filename) {
echo "Saving report to $filename...\n";
}
}
// 符合 SRP 的设计
class ReportGenerator {
public function generateReport() {
echo "Generating report...\n";
}
}
class ReportSaver {
public function saveToFile($filename) {
echo "Saving report to $filename...\n";
}
}
Go 示例:
// 不符合 SRP 的设计
type Report struct{}
func (r *Report) GenerateReport() {
fmt.Println("Generating report...")
}
func (r *Report) SaveToFile(filename string) {
fmt.Printf("Saving report to %s...\n", filename)
}
// 符合 SRP 的设计
type ReportGenerator struct{}
func (rg *ReportGenerator) GenerateReport() {
fmt.Println("Generating report...")
}
type ReportSaver struct{}
func (rs *ReportSaver) SaveToFile(filename string) {
fmt.Printf("Saving report to %s...\n", filename)
}
2. 开闭原则(Open/Closed Principle, OCP)
定义:
软件实体(类、模块、函数等)应该对扩展开放,对修改关闭。
核心思想:
通过抽象化和接口实现,允许在不修改现有代码的情况下扩展功能。
示例:
PHP 示例:
abstract class Shape {
abstract public function draw();
}
class Circle extends Shape {
public function draw() {
echo "Drawing a circle\n";
}
}
class Rectangle extends Shape {
public function draw() {
echo "Drawing a rectangle\n";
}
}
// 扩展新功能时无需修改现有代码
class Triangle extends Shape {
public function draw() {
echo "Drawing a triangle\n";
}
}
Go 示例:
type Shape interface {
Draw()
}
type Circle struct{}
func (c *Circle) Draw() {
fmt.Println("Drawing a circle")
}
type Rectangle struct{}
func (r *Rectangle) Draw() {
fmt.Println("Drawing a rectangle")
}
// 扩展新功能时无需修改现有代码
type Triangle struct{}
func (t *Triangle) Draw() {
fmt.Println("Drawing a triangle")
}
3. 里氏替换原则(Liskov Substitution Principle, LSP)
定义:
子类必须能够替换其父类,并且程序的行为不会因此发生异常或错误。
核心思想:
继承关系应该是“is-a”的语义,子类不仅要继承父类的接口,还要保证行为的一致性。
示例:
PHP 示例:
abstract class Bird {
abstract public function move();
}
class Sparrow extends Bird {
public function move() {
echo "Flying\n";
}
}
class Ostrich extends Bird {
public function move() {
echo "Running\n";
}
}
Go 示例:
type Bird interface {
Move()
}
type Sparrow struct{}
func (s *Sparrow) Move() {
fmt.Println("Flying")
}
type Ostrich struct{}
func (o *Ostrich) Move() {
fmt.Println("Running")
}
4. 接口隔离原则(Interface Segregation Principle, ISP)
定义:
客户端不应该依赖它不需要的接口。换句话说,接口应该尽量细化,避免“胖接口”。
核心思想:
将大而全的接口拆分为多个小而专的接口。
示例:
PHP 示例:
interface Workable {
public function work();
}
interface Eatable {
public function eat();
}
class HumanWorker implements Workable, Eatable {
public function work() {
echo "Working\n";
}
public function eat() {
echo "Eating\n";
}
}
class RobotWorker implements Workable {
public function work() {
echo "Working\n";
}
}
Go 示例:
type Workable interface {
Work()
}
type Eatable interface {
Eat()
}
type HumanWorker struct{}
func (hw *HumanWorker) Work() {
fmt.Println("Working")
}
func (hw *HumanWorker) Eat() {
fmt.Println("Eating")
}
type RobotWorker struct{}
func (rw *RobotWorker) Work() {
fmt.Println("Working")
}
5. 依赖倒置原则(Dependency Inversion Principle, DIP)
定义:
高层模块不应该依赖低层模块,二者都应该依赖于抽象;抽象不应该依赖细节,细节应该依赖抽象。
核心思想:
通过引入抽象层,解耦高层模块和低层模块。
示例:
PHP 示例:
interface Car {
public function drive();
}
class BMW implements Car {
public function drive() {
echo "Driving BMW\n";
}
}
class Driver {
private $car;
public function __construct(Car $car) {
$this->car = $car;
}
public function driveCar() {
$this->car->drive();
}
}
Go 示例:
type Car interface {
Drive()
}
type BMW struct{}
func (b *BMW) Drive() {
fmt.Println("Driving BMW")
}
type Driver struct {
car Car
}
func NewDriver(car Car) *Driver {
return &Driver{car: car}
}
func (d *Driver) DriveCar() {
d.car.Drive()
}
6. 迪米特法则(Law of Demeter, LoD)
定义:
一个对象应该对其他对象有最少的了解,或者说一个类应该只与直接的朋友通信。
核心思想:
减少类之间的耦合,避免一个类直接操作另一个类的内部细节。
示例:
PHP 示例:
class Address {
public function getCity() {
return "New York";
}
}
class Student {
private $address;
public function __construct(Address $address) {
$this->address = $address;
}
public function getCity() {
return $this->address->getCity();
}
}
class School {
public function printStudentCity(Student $student) {
echo $student->getCity() . "\n";
}
}
Go 示例:
type Address struct{}
func (a *Address) GetCity() string {
return "New York"
}
type Student struct {
address *Address
}
func NewStudent(address Address) Student {
return &Student{address: address}
}
func (s *Student) GetCity() string {
return s.address.GetCity()
}
type School struct{}
func (sch School) PrintStudentCity(student Student) {
fmt.Println(student.GetCity())
}
总结
设计模式的六大原则是构建高质量软件的基础。通过遵循这些原则,我们可以编写出更加灵活、可维护和可扩展的代码。无论是 PHP 还是 Go,这些原则都同样适用。在实际开发中,结合具体语言的特点,合理运用这些原则,可以帮助我们设计出更加优雅的系统架构。
License:
CC BY 4.0