设计模式:设计原则
1.单一职责(SRP)
单一职责原则(Single Responsibility Principle)定义:
应该有且仅有一个原因引起类的变更。
使用单一职责的优点:
1. 类的复杂性降低,实现什么职责都有清晰明确的定义;
2. 可读性提高,复杂性降低;
3.可维护性提高,可读性提高;
4.变更引起的风险降低,一个接口修改只对相应的实现类有影响,对其他的接口无影响
样例1:将用户管理拆分为两个接口,IUserBO负责用户的属性,简单地说,IUserBO的职责就是收集和反馈用户的属性信息;IUserBiz负责用户的行为,完成用户信息的维护和变更
<?php /** *Business Object(业务对象),负责用户收集和反馈用户的属性信息 */ interface IUserBo{ function setUserId(/* String */ $userId); function getUserId(); function setPassword(/* String */ $password); function setUserName(/* String */ $userName); function getUserName(); } /** *Business Logic(业务逻辑),负责用户的行为,完成用户信息的维护和变更 */ interface IUserBiz{ function changePassword(/* String */ $userId, /* String */ $password); function deleteUser(/* IUserBo */ $userBo); function mapUser(/* IUserBo */ $userBo); function addOrg(/* IUserBo */ $userBo, /* String */$orgId); function addRole(/* IUserBo */ $userBo, /* String */$roleId); } /** *Business Logic (业务逻辑),负责处理用户的行为 */ interface IUserInfo extends IUserBo, IUserBiz{ } class UserInfo implements IUserInfo(){ }
样例2:
/** *Business Object(业务对象),负责用户收集和反馈用户的属性信息 */ interface IUserBo{ function setUserId(/* String */ $userId); function getUserId(); function setPassword(/* String */ $password); function setUserName(/* String */ $userName); function getUserName(); } /** *Business Logic(业务逻辑),负责用户的行为,完成用户信息的维护和变更 */ interface IUserBiz extends IUserBo{ function changePassword(/* String */ $userId, /* String */ $password); function deleteUser(/* IUserBo */ $userBo); function mapUser(/* IUserBo */ $userBo); function addOrg(/* IUserBo */ $userBo, /* String */$orgId); function addRole(/* IUserBo */ $userBo, /* String */$roleId); } class UserBo implements IUserBo { } class IUserBiz implements IUserBiz{ }
2. 里氏替换原则(LSP)
里氏替换原则(Liskov Substitution Principle)定义:
(1)如果对每一个类型为S的对象o1,都有类型为T的对象o2,使得以T定义的所有程序P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型S是类型T的子类型。
(2)所有引用基类的地方必须能透明地使用其子类的对象。(子类可以扩展父类的功能,但不能改变父类原有的功能。)
里氏替换原则包含以下4层含义:
- 子类可以实现父类的抽象方法,但是不能覆盖父类的非抽象方法。
- 子类中可以增加自己特有的方法。
- 当子类覆盖或实现父类的方法时,方法的前置条件(即方法的形参)要比父类方法的输入参数更宽松。
- 当子类的方法实现父类的抽象方法时,方法的后置条件(即方法的返回值)要比父类更严格。
使用继承优点:
1.代码共享,减少创建类的工作量,每个子类都拥有父类的方法和属性;
2. 提高代码的重用性;
3.子类可以形似父类,但又异于父类;
4.提高代码的可扩展性;
5.提高产品或项目的开放性;
继承缺点:
1.继承是侵入性的。只要继承,就必须拥有父类的所有方法和属性;
2.降低代码的灵活性。子类必须拥有父类的属性和方法;
3.增强了耦合性。当父类的变量和方法被修改时,就需要考虑子类的修改;
在程序中尽量使用基类类型来对对象进行定义,而在运行时再确定其子类类型,用子类对象来替换父类对。
遵循里氏替换原则,尽量避免子类重写父类的方法,也尽量避免重载父类的方法,可以有效降低代码出错的可能性。
3. 依赖倒置原则(DIP)
依赖倒置原则( Dependence Inversion Principle,DIP)定义:
1. 高层不应该依赖低层模块,两者都应该依赖其抽象、
2. 抽象不应该依赖细节
3. 细节应该依赖抽象
实现规则:
1. 每个类尽量都有接口或抽象类,或者抽象类和接口两者都具备
2. 变量的表面类型尽量是接口或抽象类
3. 任何类都不应该从具体类派生
4. 尽量不要复写基类的方法
5. 结合里氏替换原则使用
样例代码:
<?php interface IDriver { function drive(ICar $car); } interface ICar { function run(); } class Benz implements ICar { function run(){ echo "奔驰开动了"; } } class BMW implements ICar { function run(){ echo "宝马开动了"; } } class Driver implements IDriver { function drive(ICar $car){ $car->run(); } } $car_1 = new BMW(); (new Driver())->drive($car_1);
4. 接口隔离原则
接口隔离原则定义:
1. 客户端不应该依赖它不需要的接口。
2. 类间的依赖关系应该监理在最小接口上
实现规范:
1. 接口尽量小,但是要有限度。对接口进行细化可以提高程序设计灵活性 是不挣的事实,但是如果过小,则会造成接口数量过多,使设计复杂化。所以一定要适度。
2. 为依赖接口的类定制服务,只暴露给调用的类它需要的方法,它不需要的方法则隐藏起来。只有专注地为一个模块提供定制服务,才能建立最小的依赖关系。
3. 提高内聚,减少对外交互。使接口用最少的方法去完成最多的事情。
5. 迪米特法则/最少知识原则
迪米特法则( Law of Demeter, LoD)/最少知识原则( Least Knowledge Principle, LKP)定义:
一个对象应该对其他对象有最少的了解,即一个类应该对自己需要耦合或调用的类知道的最少。
6. 开闭原则
开闭原则 定义:
一个软件实体如类、模块、和函数应该对扩展开发,对修改关闭。
设计模式
1. 创建设计模式(Creational Patterns)
用于创建对象时的设计模式。更具体一点,初始化对象流程的设计模式。当程序日益复杂时,需要更加灵活地创建对象,同时减少创建时的依赖。而创建设计模式就是解决此问题的一类设计模式。