CSDN博客地址 https://blog.csdn.net/weixin_47053123
Github项目下载地址https://github.com/MaBo2420935619
设计模式七大原则
UML图中,绿线标识继承或者实现,白线表示依赖关系
原则并不是孤立存在的,它们相互依赖,相互补充。
单一职能原则
单一职责原则(Single Responsibility Principle) SRP
单一职责原则好处
- 降低类的复杂性 每个类实现单一职责,并且单一职责都有清楚明确的定义,复杂性当然降低。
- 提高可读性
类的复杂性降低了,当然提高了可读性了。 - 提高可维护性
类的复杂性降低,可读性好,当然好维护。 - 提高扩展性
通俗点的话来说就是一个类只干一件事,或者一个方法只干一件事。
代码这里不再做过多的演示
接口隔离原则
客户端不应该依赖它不需要的接口
类间的依赖关系应该建立在最小的接口上
利用马,和鱼的例子还说名。
马需要吃饭和走路
鱼需要吃饭和游动
设计的实现接口如下
/**
* @Author mabo
* @Description 接口隔离原则
*/
public class InterfaceIsolation {
//吃
interface Eat{
public void eat();
}
//走路
interface Walk{
public void walk();
}
//游动
interface Swim {
public void swim();
}
//马在吃和走路
class Horse implements Eat , Walk{
@Override
public void eat() {
System.out.println("马在吃");
}
@Override
public void walk() {
System.out.println("马在走");
}
}
//鱼在吃和游
class Fish implements Eat ,Swim{
@Override
public void eat() {
System.out.println("鱼在吃");
}
@Override
public void swim() {
System.out.println("鱼在游");
}
}
}
倒转置换原则
依赖倒转(倒置)的中心思想是面向接口编程
依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类。
使用接口或抽象类的目的是:制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
倒转置换可以有三种写法
这里用小猫小狗跑来做示例
1.接口作为方法参数
/**
* @Author mabo
* @Description 依赖倒转
* @Description 方法接口作为参数
*/
public class DependencyInversion1 {
private interface Animal {
public void run();
}
private static class Action {
public void go(Animal animal) {
animal.run();
}
}
private static class Dog implements Animal {
@Override
public void run() {
System.out.println("小狗在跑");
}
}
private static class Cat implements Animal {
@Override
public void run() {
System.out.println("猫在跑");
}
}
public static void main(String[] args) {
Action action = new Action();
action.go(new Dog());
action.go(new Cat());
}
}
2.接口作为属性,利用构造方法初始化接口
/**
* @Author mabo
* @Description 依赖倒转
* @Description 类参数为接口
*/
public class DependencyInversion2 {
private interface Animal{
public void run();
}
private static class Action{
private Animal animal;
/**
* @Author mabo
* @Description 通过构造方法传入接口
*/
public Action(Animal animal) {
this.animal=animal;
}
public void go() {
animal.run();
}
}
private static class Dog implements Animal {
@Override
public void run() {
System.out.println("小狗在跑");
}
}
private static class Cat implements Animal {
@Override
public void run() {
System.out.println("猫在跑");
}
}
public static void main(String[] args) {
Action dogAction=new Action(new Dog());
dogAction.go();
Action catAction=new Action(new Cat());
catAction.go();
}
}
3.接口作为属性,利用set方法初始化接口
/**
* @Author mabo
* @Description 依赖倒转
* @Description setter方法传入接口
*/
public class DependencyInversion3 {
private interface Animal{
public void run();
}
private static class Action{
private Animal animal;
public void setAnimal(Animal animal) {
this.animal = animal;
}
//通过构造方法传入接口
public void go() {
animal.run();
}
}
private static class Dog implements Animal {
@Override
public void run() {
System.out.println("小狗在跑");
}
}
private static class Cat implements Animal {
@Override
public void run() {
System.out.println("猫在跑");
}
}
public static void main(String[] args) {
Action dogAction=new Action();
dogAction.setAnimal(new Dog());
dogAction.go();
Action catAction=new Action();
catAction.setAnimal(new Cat());
catAction.go();
}
}
里氏替换原则
里氏替换原则的主要作用
- 里氏替换原则是实现开闭原则的重要方式之一。
- 它克服了继承中重写父类造成的可复用性变差的缺点。
- 它是动作正确性的保证。即类的扩展不会给已有的系统引入新的错误,降低了代码出错的可能性。
- 加强程序的健壮性,同时变更时可以做到非常好的兼容性,提高程序的维护性、可扩展性,降低需求变更时引入的风险。
里氏替换原则的定义可以总结如下:
- 子类可以实现父类的抽象方法,但不能覆盖父类的非抽象方法
- 子类中可以增加自己特有的方法
- 当子类的方法重载父类的方法时,方法的前置条件(即方法的输入参数)要比父类的方法更宽松
- 当子类的方法实现父类的方法时(重写/重载或实现抽象方法),方法的后置条件(即方法的的输出/返回值)要比父类的方法更严格或相等
这里用燕子和麻雀继承鸟做说明
/**
* @Author mabo
* @Description 里氏置换原则
*/
public class RichterSubstitutionPrinciple {
public static void main(String[] args) {
Bird bird1 = new Swallow();
Bird bird2 = new Sparrow();
bird1.setSpeed(120);
bird2.setSpeed(120);
System.out.println("如果飞行300公里:");
try {
System.out.println("燕子将飞行" + bird1.getFlyTime(300) + "小时.");
System.out.println("几维鸟将飞行" + bird2.getFlyTime(300) + "小时。");
} catch (Exception err) {
System.out.println("发生错误了!");
}
}
//鸟类
public static class Bird {
double flySpeed;
public void setSpeed(double speed) {
flySpeed = speed;
}
public double getFlyTime(double distance) {
return (distance / flySpeed);
}
}
//燕子类
public static class Swallow extends Bird {
}
//麻雀
public static class Sparrow extends Bird {
//不应该重写父类方法
// public void setSpeed(double speed) {
// flySpeed = 0;
// }
public void getFar(double distance){
System.out.println(distance);
}
}
}
合成/聚合复用原则
合成复用原则(Composite Reuse Principle,CRP)又叫组合/聚合复用原则(Composition/Aggregate Reuse Principle,CARP)
简单理解合成复用就是将现有对象作为当前类的成员变量,开发中很常见
开闭原则
开闭原则
- 类的改动是通过增加代码进行的,不是修改源代码。
- 抽象化是开闭原则的关键。
这里用三角形和圆继承图像来说明
/**
* @Author mabo
* @Description 开闭原则
*/
public class OpenClosePrinciple {
static abstract class Sharp{
public abstract void paint();
}
static class DrawingEditor{
public void draw(Sharp sharp){
sharp.paint();
}
}
static class Rectangle extends Sharp{
@Override
public void paint() {
System.out.println("画一个矩形");
}
}
static class Circle extends Sharp{
@Override
public void paint() {
System.out.println("画一个圆形");
}
}
public static void main(String[] args) {
DrawingEditor drawingEditor=new DrawingEditor();
drawingEditor.draw(new Circle());
drawingEditor.draw(new Rectangle());
}
}
迪米特法则
迪米特法则又叫做最少知道原则,就是说一个对象应当对其它对象有尽可能少的了解,不要和陌生人说话。
强调只和朋友说话,不和陌生人说话。这里的朋友指的是:出现在成员变量,方法输入,输出参数中的类称为成员朋友类,而出现在方法体内部的类不属于朋友类。
迪米特法则初衷在于降低类之间的耦合。由于每个类尽量减少对其它类的依赖,因此。很容易使得系统的功能模块独立,相互之间不存在(或很少有)依赖关系。
错误的例子
/**
* @Author mabo
* @Description 迪米特法则
* @Description 直接朋友 要求依赖的类是成员变量,方法参数,方法返回值
* @Description 最好将自己依赖的类作为成员变量,叫做类之间是朋友关系
* @Description 对自己依赖的类,最好直接调用类的方法,而不是将类作为局部变量
*/
public class DemeterBadExample {
private static class Student{
private List list=new ArrayList();
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public void addList(){
list.add(1);
}
}
public static void main(String[] args) {
Student student=new Student();
student.addList();
List list = student.getList();
int size = list.size();
System.out.println(size);
}
}
正确写法
/**
* @Author mabo
* @Description 迪米特法则
* @Description 直接朋友 要求依赖的类是成员变量,方法参数,方法返回值
* @Description 最好将自己依赖的类作为成员变量,叫做类之间是朋友关系
* @Description 对自己依赖的类,最好直接调用类的方法,而不是将类作为局部变量
*/
public class DemeterPrinciple {
//将需要依赖的类作为成员变量
private static Student student=new Student();
private static class Student{
private List list=new ArrayList();
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
public void addList(){
list.add(1);
}
public int size(){
return list.size();
}
}
public static void main(String[] args) {
student.addList();
// List list = student.getList();
// int size = list.size();
int size = student.size();
System.out.println(size);
}
}