Posts 设计模式原则
Post
Cancel

设计模式原则

设计模式原则

1.单一职责原则

1
2
3
4
5
6
7
单一职责原则简称SRP【Single Responsibility Principle】,设计模式最基本原则。

简单的说就是一个类只负责一件事,只有一个因素能引起类的变化。

我们可以理解为类的专注吧,只有专注于解决某一件事才能专业。

如果一个类负责多件事,这会千万类之间的耦合性高,不方便代码的扩展。

2.里氏替换原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
里氏替换原则简称LSP【Liskov Substitution Principle】是个什么鬼?名字叫的这么洋气!

先来看下里氏替换原则的定义:

定义1:如果对第一个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在
      所有对象O1都替换成O2时,程序P的行为没有发生变化,那么类型T2是T1的子类型;

定义2:所有引用基类的地方必须能透明地使用其子类的对象;

定义往往总是官方绕口难懂的,换句话表达里氏替换原则说的就是在类的继承中,对于父类已经实
现好的方法A,子类尽量不要重写A方法或者重载A方法。为什么?为什么要有这样的建议?

比如说:有一个功能P1,是由类X来完成的,现在要升级功能P1到P,P功能是P1功能和P2功能的组
       合,升级的功能P是由 类X 和 子类Y 共同完成的,所以在 子类Y 完成功能P2时,有可
       能导致P1功能发生故障。【有可能重写了 类X 中的方法】

       所以为了避免此类情况的发生,子类Y 在继承 类X 时除添加新方法完成功能P2外,尽量
       不要重写或者重载 类X 中的方法。

       案例:

       1.我需要在类中实现两数相加

            class X{

                public int func1( int a, int b ){
                    return a+b;
                }

            }


            public class Client{

                public static void main(String[] args){

                    X x = new X();

                    System.out.println( "100+50=" + x.func1(100,50) );

                }
            }


            运行结果:

            100+50= 150
            --------------------

       2.现在需要写一个类,不仅要实现两数相加,更要实现相数相减后再加上10

            class Y extends X{

                public int func1( int a, int b ){
                    return a-b;
                }

                public int func2( int a, int b ){
                    return func1(a,b)+10;
                }

            }


            public class Client{

                public static void main(String[] args){

                    Y y = new Y();

                    System.out.println( "100+50=" + y.func1(100,50) );

                    System.out.println( "100-50+10=" + y.func2(100,50) );

                }
            }


            运行结果:

            100+50= 50

            100-50+10= 60
            -------------

       结论:子类Y 重写了父类X中的方法func1, 导致的结果是子类Y失去两数相加的功能


里氏替换原则包含以下含义:

    1.子类可以实现父类中的抽象方法,但不能覆盖父类中的非抽象方法;
    2.子类可以新增加特有的方法来扩展功能;
    3.当子类的方法重载父类方法时,方法的形参要比父类方法的形参宽松;
    4.当子类的方法实现父类的抽象方法时,方法的返回值要比父类更严格;


PS: 此原则之所以被称为里氏替换原则,是因为它是由麻省理工学院的Barbara Liskov提出
    来的芭芭拉·里斯科夫(Barbara Liskov)是一位非常牛逼的女性程序员,可以度娘下。

3.依赖倒置原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
依赖倒置原则简称DIP【Dependency Inversion Principle】,其核心思想便是面向接口编程

依赖倒置原则定义:

高层模块不应该依赖低层模块,二者都应该依赖其抽象;抽象不应该依赖细节;细节应该依赖抽象。

啊.... 正如我所说,定义总是官方绕口难懂的...

简单来说依赖倒置原则就是希望我们写的类A依赖其它类B时,类B最好是一个抽象的存在【接口】

案例:

    1.需要写个小机器人,能说出苹果的味道

        class Apple{

            public String getTaste(){

                return "Apple's taste may be sweet or sour.";

            }

        }

        class Robot{

            public void say(Apple apple){

                System.out.println( "Start speaking: "+apple.getTaste() );
            }
        }

        public class Client{

            public static void main(String[] args){

                Robot robot = new Robot();

                Apple apple = new Apple();

                Robot.say(apple);

            }

        }

    输出结果:

        Start speaking: Apple's taste may be sweet.
        ---------------------------------------------------


    2.这时候我需要小机器人,告诉我葡萄是什么味道。我是新加一个方法?这显然不是好的办法...

        interface Fruit{
            public String getTaste();
        }

        class Apple implements Fruit{

            public String getTaste(){
                return "Apple's taste may be sweet.";
            }

        }

        class Grape implements Fruit{

            public String getTaste(){
                return "Grape's taste may be sour."
            }
        }

        class Robot{

            public void Say(Fruit fruit){
                System.out.println( "Start speaking: "+fruit.getTaste() );
            }

        }

        public class Client{

            public static void main(String[] args){

                Robot robot = new Robot();

                Apple apple = new Apple();

                Grape grape = new Grape();

                robot.say(apple);

                robot.say(grape);
            }
        }

        运行结果:

            Start speaking: Apple's taste may be sweet.

            Start speaking: Grape's taste may be sour.
            -------------------------------------------


以上传递依赖关系使用了接口传递,使用接口传递极大的降低了类之间的耦合性

依赖倒置原则告诉我们:

    1. 低层模块【非业务模块】尽量要有抽象类或者接口;
    2. 变量申明也尽量抽象;

4.接口隔离原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
接口隔离原则简称ISP【Interface Segregation Principle】。

接口隔离可以使接口最小专,单一化,有利于实现类的适用笥。

定义:
    客户端不应该依赖它不需要的接口;一个类对另一个类的依赖应该建立在最小的接口上。


换句话说,如果类A通过接口I依赖类B, 类X也通过接口I依赖类Y,接口I对于类B,类Y来说并非最小接口

也就是说类B,类Y实现了接口I中多余的方法,这是不可取的,应该将接口I拆分为两接口I1、I2,让类B、

类Y分别实现接口I1,I2,这样类A通过接口I1来依赖类B,类X通过接口I2来依赖类Y。



接口隔离原则含义:

    1. 建立单一接口,避免庞大臃肿的接口,从而避免实现类实现无关的方法;

5.迪米特法则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
迪米特法则简称LoD【Law of Demeter】又是什么鬼?洋气的名字又出现鸟......

迪米特法则定义:

    一个对象应该对其它对象保持最少的了解。


这个定义好懂,官方都这样说简单明白的话就不那么烧脑了。迪米特法则宗旨是尽量降低类与类之间的耦合。

类与类之间的关系越密切,耦合越大,当一个类改变时,对另一个类的影响就越大......

程序设计中的原则是:低耦合,高内聚。这也体现了面对象的三大特性的目标。


迪米特含义:

    1. 只与自己有直接关系的类进行耦合;

6.开闭原则

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
开闭原则简称OCP【Open-Closed Principle】。

开闭原则定义:

    一个软件的实体如类、模块和函数应该对扩展开放,对修改关闭。


在软件的生命周期内,因为变化、升级和维护等因素需要对代码进行修改更新,这可能会带来一些新的BUG,

日积月累下去,可能会导致项目不得不进行重构。

如何才能遵循开闭原则? 做好前5项原则,自然会做到开闭。


开闭原则含义:

    1. 用抽象构建框架,用实现扩展细节;
This post is licensed under CC BY 4.0 by the author.

【算法解忧】零后置,保持数字相对排序

【创建型】单例模式详解