一、三大特性
1、封装
字面意思就是将内容装到某个容器中,并进行密封保存。在面向对象思想中,指将数据和对数据的操作捆绑到一起,形成对外界的隐蔽,同时对外提供可以操作的接口。
- 封装是从对象实体抽象形成类的过程
- 封装的目的是让使用者只知道类能做什么,而不知道类是怎么做的
- 封装特性也明确了类与对象的职责:类负责处理业务逻辑,对象只要调用实现
2、继承
继承是一种实现代码复用和扩展性的重要机制。它允许一个类(称为子类或派生类)继承另一个类(称为父类或基类)的属性(成员变量)和方法(成员函数)。子类通常可以访问父类的所有属性和部分方法(私有方法private function 不可访问),并且可以添加自己的新属性和方法,或者重写父类的某些方法。
在PHP、JAVA中,子类只能直接继承一个父类,也就是单继承但可以通过接口(interface)实现类似多继承的效果。
3、多态
多态性是指相同的操作或函数可作用于多种类型的对象上并获得不同的结果。
多态通常有以下实现方式:
1、方法重写(Override):子类重写父类的方法,当调用该方法时,将执行子类的方法而不是父类中的方法。这是多态最常见的实现方式。当不希望被重写,可以使用final关键字。
2、接口实现:当一个类实现了某个接口,则该类可以被当作该接口的对象来处理。这允许不同的类来实现相同的接口,从而以统一的方式来处理这些类的对象。
3、重载(Overload):虽然重载本身并不直接体现多态性,但重载和多态可以一起使用,以提供对同一操作的不同实现。
二、重要概念
1、抽象类(Abstract Class)
抽象类是不能被实例化的类,它包含一个或多个抽象方法。这些方法在抽象类中没有具体实现,需要在其子类中实现。抽象类的主要目的是为子类提供一个通用的接口。
定义抽象类时,需要注意以下几个方面:
(1). 明确抽象类的目的
通用模板:抽象类应该作为一组相关类的通用模板,定义它们的共同行为和特征。
不能实例化:抽象类是不能被实例化的,只能被继承。
(2). 抽象方法与具体方法
抽象方法:必须至少包含一个抽象方法(没有方法体的声明),子类必须实现这些抽象方法。
具体方法:可以包含具体方法(有方法体),子类可以直接使用这些方法或进行重写。
(3). 设计子类必须实现的方法
必要性:抽象方法应该是所有子类必须实现的功能,确保子类遵守特定的行为规范。
灵活性:如果某些方法可以有默认实现,考虑将其定义为具体方法,而不是抽象方法。
(4). 构造函数
初始化:抽象类可以有构造函数,用于初始化共有属性或进行必要的设置。
子类调用:子类可以通过parent关键字调用抽象类的构造函数。
(5). 字段和常量
成员变量:抽象类可以包含成员变量,子类可以继承和使用这些变量。
常量:抽象类可以包含常量,用于定义全局不变的值。
(6). 访问修饰符
不能合并使用:abstract不能与private、static、final等修饰符并列修饰同一个方法。
(7). 避免过度复杂化
简洁性:抽象类应该保持简洁,避免过度复杂的设计。尽量只包含核心功能,让子类去扩展和实现具体的业务逻辑。
高内聚低耦合:确保抽象类内部高度内聚,同时与其他类低耦合,以便子类可以灵活重用和扩展。
2、接口(interface)
接口是一种完全抽象的类型,它定义了一组方法,但不包含这些方法的具体实现。接口用于声明类应该具备哪些方法,具体的实现则由实现接口的类来提供。接口提供了一种契约式的编程方式,确保类遵循某种特定的行为。
定义接口时,需要注意以下几个方面:
(1). 接口的命名
命名规范:接口的命名应遵循一定的命名规范,通常以Interface结尾,例如LoggerInterface。
易读性:接口名称应清晰、易读,能够准确描述接口的功能。
(2). 方法声明
抽象方法:接口中的所有方法都是抽象的,只包含方法签名,没有方法体。
公共方法:接口中的方法默认是public的,不需要显式声明为public。
(3). 属性和常量
属性:接口中不能定义属性
常量:接口中可以包含常量,常量的值在接口定义时就确定,并且是不可修改的。
(4). 单一职责
职责单一:每个接口应该有单一的职责,避免将不相关的功能组合在一个接口中。接口应尽量小而精,不要过于臃肿。
(5). 接口继承
多继承:一个接口可以继承多个其他接口,从而组合多个接口的功能。
扩展功能:子接口可以在继承父接口的方法基础上添加新的方法声明。
(6). 使用接口实现多态
多态性:接口允许不同类以同一种方式进行操作,从而实现多态性。实现接口的类必须实现接口中定义的所有方法。
(7). 接口的灵活性
实现细节隔离:接口定义了实现类必须遵循的契约,但不关心具体的实现细节。通过接口,可以在不修改客户端代码的情况下改变具体实现类。
3、复用类(trait)
复用类是指在软件开发过程中,设计得足够通用和灵活,以便在多个不同的应用程序或系统中重用的类。复用类的目的是提高代码的复用性、可维护性和可扩展性,减少重复劳动,提高开发效率。
定义复用类时,需要注意以下几个方面:
(1).单一职责原则:确保类具有单一职责,每个类应该只负责一种功能或行为。这有助于提高代码的清晰度和可维护性,并使类更容易被复用。
(2).高内聚低耦合:确保类内部的各个组件彼此相关联,完成一个特定的功能,同时类之间的耦合度尽量降低。这样可以提高代码的灵活性和可扩展性。
(3).良好的接口设计:如果是通过接口进行类的复用,要确保接口定义清晰、简洁,不包含过多的方法或属性。接口应该只包含客户端代码需要的最小接口,避免接口膨胀和不必要的复杂性。
(4).可扩展性:考虑到类可能会被不同的项目或场景所复用,要确保类具有良好的扩展性,能够方便地进行修改和扩展,同时不影响已有功能的稳定性。
三、设计模式
1、单例模式
单例模式的类只能在一次运行中产生一个对象。
设计方案,简称三私一公:
- 私有化构造方法:此时该对象无法被实例化
- 私有化克隆方法:该对象不能被克隆
- 公有化静态方法:对外提供的获取类的接口
- 私有化静态属性:保存已经产生的对象
#PHP代码实例
class Singleton {
// 声明一个静态变量来保存类的实例
private static $instance;
// 私有构造函数,防止外部实例化
private function __construct() {
// 初始化代码...
}
// 私有克隆方法,防止克隆
private function __clone() {
}
// 静态方法,用于获取类的实例
public static function getInstance() {
if (self::$instance === null) {
self::$instance = new self();
}
return self::$instance;
}
// 类的其他方法...
public function someMethod() {
// ...
}
}
// 使用示例
$instance1 = Singleton::getInstance();
$instance2 = Singleton::getInstance();
// $instance1 和 $instance2 实际上是同一个实例
if ($instance1 === $instance2) {
echo "是同一个实例";
} else {
echo "不是同一个实例";
}
2、工厂模式
指像工厂一样流水线生产对象,由一个地方生产对象,其他位置不需要额外实例化对象,从而可以方便后期代码统一维护。
class Man{
public function display(){
echo "Man"
}
}
class Woman{
public function display(){
echo "Woman"
}
}
class HumanFactory{
public static function getInstance($name){
switch($name){
case 'Man':
return new Man();
case 'Woman':
return new Woman();
}
}
}
$man = HumanFactory::getInstance('Man');
3、控制反转
控制反转的核心思想是将对象的创建和依赖的管理交给外部容器,而不是由对象自身来管理它们的依赖。这样可以提高代码的可测试性、可维护性和灵活性。
依赖注入是实现控制反转的一种常见方式,通过将对象的依赖注入到对象中,而不是让对象自己创建或查找它们的依赖。
依赖注入有三种常见方式:
- 构造函数注入:通过构造函数传递依赖。
- 方法注入:通过类的方法传递依赖。
- 属性注入:通过设置类的属性传递依赖。
interface LoggerInterface {
public function log(string $message): void;
}
class FileLogger implements LoggerInterface {
public function log(string $message): void {
echo "Logging to a file: $message";
}
}
class DatabaseLogger implements LoggerInterface {
public function log(string $message): void {
echo "Logging to a database: $message";
}
}
class UserController {
private $logger;
// 通过构造函数注入LoggerInterface依赖
public function __construct(LoggerInterface $logger) {
$this->logger = $logger;
}
public function createUser(string $username): void {
// 创建用户逻辑
echo "User $username created.\n";
$this->logger->log("User $username created.");
}
}
// 使用FileLogger
$fileLogger = new FileLogger();
$userController = new UserController($fileLogger);
$userController->createUser('Alice');
// 使用DatabaseLogger
$databaseLogger = new DatabaseLogger();
$userController = new UserController($databaseLogger);
$userController->createUser('Bob');