一.设计模式的目的
在编写软件时,为了提高①代码重用性②可读性③可扩展性④可靠性⑤高内聚,低耦合的特性。设计模型原则,是程序员在编程时,应当遵守的原则,也是各种设计模型的基础。
二.单一职责原则
1.含义:
一个类应该只负责一项职责
2.代码演示
public class Hello {
public static void main(String[] args){
Vehicle.run("马萨拉蒂");
Vehicle.run("波音737");
}
}
class Vehicle{
public static void run(String vehicle){
System.out.println(vehicle+"在公路上跑...");
}
}
//马萨拉蒂在公路上跑...
//波音737在公路上跑...
3.分析:
如果地上跑的,天上飞的,水上游的都同用同一个类的话,那么单从这个类的表示上就不合适
4.代码修改
public class Hello {
public static void main(String[] args){
Vehicle.runRoad("马萨拉蒂");
Vehicle.runAir("波音737");
}
}
class Vehicle{
public static void runRoad(String vehicle){
System.out.println(vehicle+"在公路上跑...");
}
public static void runAir(String vehicle) {
System.out.println(vehicle + "在天上飞...");
}
}
//马萨拉蒂在公路上跑...
//波音737在天上飞...
5.总结:
①降低类的复杂度,一个类只负责一项职责
②提高类的可读性,可维护性
③降低变更引起的风险
④通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中的方法数量足够少,可以在方法级别保持单一职责原则
三.接口隔离原则
1.含义:
一个类对另一个类的依赖应该建立在最小的接口上
2.代码演示
public class Hello {
public static void main(String[] args){
C c=new C();
c.depend2(new A());
D d=new D();
d.depend4(new B());
}
}
interface interface1{
void function01();
void function02();
void function03();
void function04();
void function05();
}
class A implements interface1{
public void function01(){
System.out.println("A用了function01");
}
public void function02(){
System.out.println("A用了function02");
}
public void function03(){
System.out.println("A用了function03");
}
public void function04(){
System.out.println("A用了function04");
}
public void function05(){
System.out.println("A用了function05");
}
}
class B implements interface1{
public void function01(){
System.out.println("B用了function01");
}
public void function02(){
System.out.println("B用了function02");
}
public void function03(){
System.out.println("B用了function03");
}
public void function04(){
System.out.println("B用了function04");
}
public void function05(){
System.out.println("B用了function05");
}
}
class C{
public void depend1(interface1 i){
i.function01();
}
public void depend2(interface1 i){
i.function02();
}
public void depend3(interface1 i){
i.function03();
}
}
class D{
public void depend1(interface1 i){
i.function01();
}
public void depend4(interface1 i){
i.function04();
}
public void depend5(interface1 i){
i.function05();
}
}
3.分析:
C通过A实现方法的调用,A实现了interface1的接口;D通过B实现方法的调用,B实现了interface1的接口;其中A和B重写了function1、2、3、4、5,但在主函数中C只需要A的function1、2、3而B只需要D的1、4、5,那么这样看来A和B中有不需要的实现方法,既然不需要,也考虑到低耦合那么可以把没有用到的方法分开
4.代码修改
public class Hello {
public static void main(String[] args) {
C c = new C();
c.depend1(new A());
c.depend2(new A());
c.depend3(new A());
D d = new D();
d.depend1(new B());
d.depend4(new B());
d.depend5(new B());
}
}
interface interface1 {
void function01();
}
interface interface2 {
void function02();
void function03();
}
interface interface3 {
void function04();
void function05();
}
class A implements interface1, interface2 {
public void function01() {
System.out.println("A用了function01");
}
public void function02() {
System.out.println("A用了function02");
}
public void function03() {
System.out.println("A用了function03");
}
}
class B implements interface1, interface3 {
public void function01() {
System.out.println("B用了function01");
}
public void function04() {
System.out.println("B用了function04");
}
public void function05() {
System.out.println("B用了function05");
}
}
class C {
public void depend1(interface1 i) {
i.function01();
}
public void depend2(interface2 i) {
i.function02();
}
public void depend3(interface2 i) {
i.function03();
}
}
class D {
public void depend1(interface1 i) {
i.function01();
}
public void depend4(interface3 i) {
i.function04();
}
public void depend5(interface3 i) {
i.function05();
}
}
5.总结
一个类对另一个类的依赖应该建立在最小的接口上,以此原则对接口进行合理拆分
四.依赖转置原则
1.含义:
①高层模块不应该依赖底层模块,二者应该依赖其抽象
②抽象不依赖细节,细节依赖抽象
③依赖转置的中心思想是面向接口编程
④设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比细节为基础的架构要稳定的多
⑤使用接口或抽象类的目的是制定好规范,而不涉及任何具体操作,把展现细节的任务交给他们的实现类去完成
2.代码演示
public class Hello {
public static void main(String[] args) {
Person.receive(new Email());
}
}
class Email{
public static void getMessage(){
System.out.println("收到了来自Email的消息");
}
}
class Person{
public static void receive(Email email){
email.getMessage();
}
}
//收到了来自Email的消息
3.分析
在现实生活中,消息不会只来自Email,也可能来自微信,qq等其他途径。当我们代码像上面演示写的话,Person这个类里的receive方法只能接受Email对象,如果想对接受来自其他地方的消息提示,则需要再构建新的方法,这样就增加了工作量,不利于维护。
4.代码修改
public class Hello {
public static void main(String[] args) {
Person.receive(new Email());
Person.receive(new Wechat());
}
}
interface IReceive{
public void getMessage();
}
class Email implements IReceive{
public void getMessage(){
System.out.println("收到了来自Email的消息");
}
}
class Wechat implements IReceive{
public void getMessage(){
System.out.println("收到了来自Wechat的消息");
}
}
class Person{
public static void receive(IReceive ireceive){
ireceive.getMessage();
}
}
//收到了来自Email的消息
//收到了来自Wechat的消息
5.总结
①底层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好
②变量的声明类型尽量使抽象类或接口,这样我们的变量引用或实际对象间,就存在一个缓冲层,利于程序扩展和优化
③继承时遵循里氏替换原则
五.里氏替换原则
1.含义
①所有引用基类的地方必须能够透明地使用其子类的对象
②子类中尽量不要重写父类的方法
③继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合、组合、依赖来解决问题
2.代码展示
public class Hello {
public static void main(String[] args) {
A a=new A();
System.out.println("1+1="+a.sum(1,1));
B b=new B();
System.out.println("1+1="+b.sum(1,1));
System.out.println("1-1="+b.minus(1,1));
}
}
class Base{
public int sum(int a,int b){
return a+b;
}
}
class A extends Base{
A(){
System.out.println("调用A");
}
}
class B extends Base{
B(){
System.out.println("调用B");
}
public int minus(int a,int b){
return a-b;
}
}
//调用A
//1+1=2
//调用B
//1+1=2
//1-1=0
3.分析
A和B都继承了Base,且都没有修改sum方法
4.总结
如果A和B拥有相同的方法,尽量构建多一个更加通俗的基类,采用依赖、聚合、组合等关系代替
六.开闭原则
1.含义:
①开闭原是编程中最基础、最重要的设计原则。之前学习的几个原则组合起来可以集中体现这个原则
②一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节
③当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有代码来实现变化
④编程中遵循其他原则,以及使用设计模式的目的就是遵循开闭原则
2.代码演示:
public class Hello {
public static void main(String[] args) {
DrawShape drawShape=new DrawShape();
drawShape.draw(new Rectangle());
drawShape.draw(new Circle());
}
}
class Shape{
int type;
}
class Rectangle extends Shape{
Rectangle(){
super.type=1;
}
}
class Circle extends Shape{
Circle(){
super.type=2;
}
}
class DrawShape {
public void drawRectangle(){
System.out.println("画了个长方形");
}
public void drawCircle(){
System.out.println("画了个圆形");
}
public void draw(Shape shape){
if(shape.type==1)
drawRectangle();
else if(shape.type==2)
drawCircle();
}
}
3.分析:
演示的代码非常繁杂,且不好维护。如果我们想添加画一个正方形,那么必须添加一个正方形的类、DrawShape添加画正方形的方法以及else if。这使得在后期需要对软件进行增添会有非常大的阻力
4.代码修改:
public class Hello {
public static void main(String[] args) {
DrawShape drawShape=new DrawShape();
drawShape.draw(new Rectangle());
drawShape.draw(new Circle());
}
}
abstract class Shape{
abstract public void draw();
}
class Rectangle extends Shape{
@Override
public void draw() {
System.out.println("画了个长方形");
}
}
class Circle extends Shape{
@Override
public void draw() {
System.out.println("画了个圆形");
}
}
class DrawShape {
public void draw(Shape shape){
shape.draw();
}
}
5.总结:
遵循开闭原则对修改代码添加功能拥有非常好的帮助,也是对前几个原则的进行的集合
七.迪米特原则
1.含义
①一个对象对其他对象保持最少的了解。因为类与类关系越密切,耦合度越大
②又称最少知道原则,即一个类对自己以来的类知道越少越好。也就是说,对于被以来的类不管多么复杂,都尽量将逻辑封装在类的内部。除了提供的public,不对外泄露任何信息
③只与直接的朋友通信,我们称出现成员变量,方法参数,方法返回值中的类为直接朋友。陌生的类最好不要以局部变量的形式出现在类的内部
2.总结
降低非直接朋友的耦合度
八.合成复用原则
1.含义
①原则是尽量使用合成/聚合的方式,而不是使用继承
九.总结
通过对七大原则的学习,可以进行的总结就是:在设计软件前首先要对类的分工进行明确,类与类之间的耦合度通过合成/聚合尽可能的减少,顾及后期的维护需要对基础类进行构建。
PS:因为刚学习的设计模式,做出来的笔记并不深入,在后续的学习中会继续添加关于这七大原则的见解。