设计模式之七大原则(一)——单一职责原则、开放-关闭原则
一、设计模式的目的
设计模式的目的是为了提高代码重用性、可读性、可扩展性、可靠性,使得程序呈现出高内聚、低耦合的特性。
- 代码重用性(相同功能的代码,不用多次编写)
- 可读性(编程规范性,便于其他程序员的阅读和理解)
- 可扩展性(当需要增加新的功能时,非常的方便,称为可维护性)
- 可靠性(当我们增加新的功能时,对原来的功能没有影响)
- 使程序呈现高内聚、低耦合的特性
二、设计模式的七大原则
我们在设计一些设计模式时,一般遵循如下七项基本原则,它们分别是:
- 单一职责原则 (Single Responsibility Principle)
- 开放-关闭原则 (Open-Closed Principle)
- 里氏替换原则 (Liskov Substitution Principle)
- 依赖倒转原则 (Dependence Inversion Principle)
- 接口隔离原则 (Interface Segregation Principle)
- 迪米特法则(Law Of Demeter)
- 组合/聚合复用原则 (Composite/Aggregate Reuse Principle)
1.单一职责原则
单一职责原则的核心就是控制类的粒度大小、将对象解耦、提高其内聚性。如果遵循单一职责原则将有以下优点。
- **降低类的复杂度。**一个类只负责一项职责,其逻辑肯定要比负责多项职责简单得多。
- **提高类的可读性。**复杂性降低,自然其可读性会提高。
- **提高系统的可维护性。**可读性提高,那自然更容易维护了。
- **变更引起的风险降低。**变更是必然的,如果单一职责原则遵守得好,当修改一个功能时,可以显著降低对其他功能的影响。
简单说明一下,首先我们可以对某个类来说,即一个类应该只负责一项职责。如类A负责两个不同职责: 职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2。
以下假设一个场景并用代码演示(项目代码名称为SRP):
有一个鸟类,它会飞翔,用一个类描述鸟类飞行这个场景:
创建类Fly.java,代码如下:
public class Fly {
public void birds(String birds){
System.out.println(birds + "会在空中飞翔");
}
}
创建运行类Client.java,代码如下:
public class Client{
public static void main(String[] args){
Fly fly = new Fly();
fly.birds("老鹰");
fly.birds("猫头鹰");
fly.birds("喜鹊");
}
}
运行结果如下所示:
老鹰会在空中飞翔
猫头鹰会在空中飞翔
喜鹊会在空中飞翔
在后来发现新问题,并不是所有的鸟类都会飞翔的,比如企鹅就不会了,修改时如果遵循单一职责原则的话,那么需要添加一个类
创建类NoFly.java,代码如下:
public class NoFly {
public void birds(String birds){
System.out.println("\n");
System.out.println(birds + "不会在空中飞翔");
}
}
修改运行类Client.java,代码如下:
public class Client{
public static void main(String[] args){
Fly fly = new Fly();
fly.birds("老鹰");
fly.birds("猫头鹰");
fly.birds("喜鹊");
NoFly noFly = new NoFly();
noFly.birds("企鹅");
}
}
运行结果如下所示:
老鹰会在空中飞翔
猫头鹰会在空中飞翔
喜鹊会在空中飞翔
企鹅不会在空中飞翔
2.开放-关闭原则
开放封闭原则就是软件实体应该对扩展开放,而对修改封闭。开放封闭原则是所有面向对象原则的核心。软件设计本身所追求的目标就是封装变化,降低耦合,而开放封闭原则正是对这一目标的最直接体现。
开放封闭原则主要体现在两个方面:
- 对扩展开放,意味着有新的需求或变化时,可以对现有代码进行扩展,以适应新的情况。
- 对修改封闭,意味着类一旦设计完成,就可以独立其工作,而不要对类尽任何修改。
如果一个软件能够满足 OCP 原则,那么它将有以下两项优点:
- 能够扩展已存在的系统,能够提供新的功能满足新的需求,因此该软件有着很强的适应性和灵活性。
- 已存在的模块,特别是那些重要的抽象模块,不需要被修改,那么该软件就有很强的稳定性和持久性
开闭原则的实现方法
- 通过“抽象约束、封装变化”来实现开闭原则
- 参数类型,引用对象尽量使用接口或抽象类,而不是现实类;
- 通过接口或抽象类为软件实体定义一个相对稳定的抽象层,一旦确定就不允许修改;
- 将相同的变化封装到一个接口或抽象类中;
- 将不同的变化封装到不同的接口或抽象类中;
以下假设一个场景并用代码演示(项目代码名称为OCP):
以商场卖东西为例:
创建类shopping.java,代码如下:
public class Shopping {
public static void main(String[] args) {
Shop shopping = new Shop();
shopping.shop(new Apple());
shopping.shop(new Pear());
shopping.shop(new Watermelon());
}
}
class Shop {
public void shop(Type s) {
if (s.type == 1) {
apple(s);
} else if (s.type == 2) {
pear(s);
} else if (s.type == 3) {
watermelon(s);
}
}
//出售苹果
public void apple(Type r) {
System.out.println(" 出售苹果 ");
}
//出售梨
public void pear(Type r) {
System.out.println(" 出售梨 ");
}
//出售西瓜
public void watermelon(Type r) {
System.out.println(" 出售西瓜 ");
}
}
class Type {
int type;
}
class Apple extends Type {
Apple() {
super.type = 1;
}
}
class Pear extends Type {
Pear() {
super.type = 2;
}
}
class Watermelon extends Type {
Watermelon() {
super.type = 3;
}
}
运行结果如下所示:
出售苹果
出售梨
出售西瓜
修改代码,改为用OCP原则:
创建代码ShoppingOCP.java,代码如下:
public class ShoppingOCP {
public static void main(String[] args) {
ShopOCP shopping = new ShopOCP();
shopping.shop(new Apple1());
shopping.shop(new Pear1());
shopping.shop(new Watermelon1());
shopping.shop(new Cherry1());
}
}
class ShopOCP {
public void shop(Type1 s) {
s.type1();
}
}
abstract class Type1 {
abstract void type1();
}
class Apple1 extends Type1 {
@Override
void type1() {
System.out.println(" 出售苹果 ");
}
}
class Pear1 extends Type1 {
@Override
void type1() {
System.out.println(" 出售梨 ");
}
}
class Watermelon1 extends Type1 {
@Override
void type1() {
System.out.println(" 出售西瓜 ");
}
}
class Cherry1 extends Type1 {
@Override
void type1() {
System.out.println(" 出售樱桃 ");
}
}
运行结果如下所示:
出售苹果
出售梨
出售西瓜
出售樱桃
把创建Type1 类做成抽象类,并提供一个抽象的 type方法,让子类去实现即可,这样我们有新的水果种类时,只需要让新的水果类继承 Type1 ,并实现 type方法即可,使用方的代码就不需要修改了, 从而满足了开闭原则。
以上代码下载请点击该链接:https://github.com/Yarrow052/Java-package.git
更多推荐
所有评论(0)