设计模式——七大原则
汇总篇
1、单一职责
对类来说的,即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责一需求变更而改变A时,可能照成职责2执行错误,所以需要将类A的粒度分解为A1,A2。
违背原则示例:
public static void run(Integer type,String vehicle) {
if (type == 1){
System.out.println(vehicle + "在公路上运行");
}else if (type == 2){
System.out.println(vehicle + "在天空飞");
}else {
System.out.println(vehicle + "在水里游");
}
}
符合原则代码:
1、这种方法没有对原来的类做大的修改,只是增加方法。
2、这里虽然没有在类这个级别上遵守单一职责原则,但是在方法级别上,仍然是遵守单一职责。
public class Only {
public static void run(String vehicle) {
System.out.println(vehicle + "在公路上运行");
}
public static void runAir(String vehicle) {
System.out.println(vehicle + "在天空飞");
}
public static void runWater(String vehicle) {
System.out.println(vehicle + "在水里游");
}
}
单一职责原则注意事项与细节:
- 降低类的复杂度,一个类只负责一项职责。
- 降低类的可读性,可维护性
- 降低变更引起的风险
- 通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责
2、接口隔离
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。
就是将一个类拥有很多接口拆成多个类较少接口,实现接口隔离,不需要引入不需要的接口。
违背原则示例:
public interface interface0{
void operation1(); // 产品
void operation2(); // 程序员1号
void operation3(); // 程序员2号
void operation4(); // 测试
void operation5(); // 运维
}
// 实现类
static class work implements interface0{
@Override
public void operation1() {}
@Override
public void operation2() {}
@Override
public void operation3() {}
@Override
public void operation4() {}
@Override
public void operation5() {}
}
符合原则代码:
public class Segregation {
/**
* ---------------------------------拆开多个接口---------------------------------------------
*/
public interface interface1{ // 产品接口
void operation1();
}
public interface interface2{ // 程序员
void operation2();
void operation3();
}
public interface interface3{ // 测试
void operation4();
}
/**
* ---------------------------------类实现接口---------------------------------------------
*/
static class B implements interface2{
@Override
public void operation2() {
System.out.println("B实现接口2的方法");
}
@Override
public void operation3() {
System.out.println("B实现接口2的方法");
}
}
}
static class B implements interface3{
@Override
public void operation4() {
System.out.println("B实现接口3的方法");
}
}
使用多个隔离的接口,比使用单个接口要好。它还有另外一个意思是:降低类之间的耦合度。由此可见,其实设计模式就是从大型软件架构出发、便于升级和维护的软件设计思想,它强调降低依赖,降低耦合。
3、依赖倒转
- 1、高层模块不应该依赖低层模块,二者都应该依赖其抽象。
- 2、抽象不应该依赖细节,细节应该依赖抽象
- 3、依赖倒转的中心思想是面向接口编程
- 4、依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类。
- 5、使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成。
违背原则代码
public static void main(String[] args) {
Person person = new Person();
Email email = new Email();
person.IReceiver(email);
}
public static class Person{ // 接收人
public void IReceiver(Email email){
System.out.println(email.info());
}
}
public static class Email{
String info(){
return "邮件信息";
}
}
此时又想接收微信消息,还要再重新修改
符合原则代码:
public static void main(String[] args) {
IReceiver iReceiver = new Email(); // 接收邮件消息
System.out.println(iReceiver.getInfo());
// 要想再接收微信
IReceiver iReceiver1 = new Weixin();
System.out.println(iReceiver1.getInfo());
}
// 定义接口
interface IReceiver{
public String getInfo();
}
/**
* ---------------------------------以下用实现类来做具体的细节操作---------------------------------------------
*/
static class Email implements IReceiver{
@Override
public String getInfo() {
// 这里实现细节
return "邮件消息";
}
}
static class Weixin implements IReceiver{
@Override
public String getInfo() {
// 这里实现细节
return "微信消息";
}
}
依赖倒转原则的注意事项和细节:
1、低层模块尽量都要有抽象类或接口,或者两者都有,程序稳定性更好。
2、变量的声明类型尽量是抽象类或接口,这样我们的变量引用和实际对象间,就存在一个缓冲层,利于程序扩展和优化
3、继承是遵守里氏代换原则。
4、里氏代换原则
一、OO中的继承性的思考和说明
-
1、继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契
约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实
现的方法任意修改,就会对整个继承体系造成破坏。 -
2、继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵
入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,
则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子
类的功能都有可能产生故障
要使用好继承,就要了解里氏代换原则
二、基本了解
- 1、在使用继承时,遵循里氏替换原则,
在子类中尽量不要重写父类的方法
- 2、里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可
以通过聚合,组合,依赖 来解决问题
。 - 3、如果对每个类型为T1的对象o1,都有类型为T2的对象o2,使得以T1定义的所有程序
P在所有的对象o1都代换成o2时,程序P的行为没有发生变化,那么类型T2是类型T1
的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象。.
就是当B类最好不要直接继承A类,去重写它,要再建一个更基础的类,两个都去继承,增强两个类的耦合性
违背原则代码
class A{
// 返回两个数的差
public int func1(int num1,int num2){
return num1 - num2;
}
}
class B extends A{
// 返回两个数的和
public int func2(int num1,int num2){
return num1 + num2;
}
@Override
public int func1(int num1, int num2) {
return super.func1(num1, num2);
}
}
符合原则代码:
public class Lsdh {
// 创建一个更加基础的类
class Base{
// 把更基础的方法和成员写到Base类
}
class A extends Base{
// 返回两个数的差
public int func1(int num1,int num2){
return num1 - num2;
}
}
class B extends Base{
// 返回两个数的和
public int func2(int num1,int num2){
return num1 + num2;
}
// 如果B需要使用A类的方法,使用组合关系
private A a = new A();
public int func3(int num1,int num2){
return a.func1(num1,num2);
}
}
}
5、开闭原则
- 1、 开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
- 2、 一个软件实体如类,模块和函数应该
对扩展开放(对提供方),对修改关闭(对使用方)
。用抽象构建框架,用实现扩展细节。 - 3、 当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 4、 编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
违背原则代码
public static void main(String[] args) {
// 画图功能
GraphicEditor graphicEditor = new GraphicEditor();
// 画一个正方形
graphicEditor.draw(1,"正方形");
}
static class GraphicEditor{
public void draw(Integer type,String draw) {
if (type == 1){
// 画正方形
}else if (type == 2){
// 画长方形
}
}
}
如果要新增功能时,会修改到旧代码,要是旧代码是别人写的,可能会牵一发而动全身,出了好几个bug
符合原则代码
public class Ocp {
public void main() {
// 画图功能
GraphicEditor graphicEditor = new GraphicEditor();
// 画一个正方形
graphicEditor.drawShape(new square());
// 如果还要再画一个长方形,不需要改代码,直接扩展
graphicEditor.drawShape(new rectangle());
}
// 要调用画图方法的类
static class GraphicEditor{
public void drawShape(draw draw) {
draw.drawFunc();
}
}
// 定义一个画图接口
interface draw{
// 画画的方法
void drawFunc();
}
// 实现画图接口,作画
class square implements draw{
@Override
public void drawFunc() {
System.out.println("画了个正方形!");
}
}
// 实现画图接口,作画
class rectangle implements draw{
@Override
public void drawFunc() {
System.out.println("画了个长方形!");
}
}
}
这个原则讲的就是,将代码写的扩展性高点,如果新增功能,不用去改旧代码,直接新增新的功能
6、迪米特法则
一、基本介绍
-
1、迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的
越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内
部。对外除了提供的public 方法,不对外泄露任何信息 -
2、一个对象应该对其他对象保持最少的了解
违法原则代码
// 咖啡类
static class coffee{
//泡咖啡
public void make(){
// 1、烧水
// 2、磨咖啡粉
// 3、泡
}
// 找秘书过来
public String secretary(){
return "过来";
}
}
public static void main(String[] args) {
coffee coffee = new coffee();
coffee.make();
coffee.secretary();
}
符合原则代码:
// 咖啡类
static class coffee{
//泡咖啡
public void make(){
// 1、烧水
// 2、磨咖啡粉
// 3、泡
}
// 找秘书,秘书泡好端过来
public String secretaryMake(){
make();
return "coffee";
}
}
public static void main(String[] args) {
// 老板想找助理干活,还想喝coffee,直接叫助理泡好过来
coffee coffee = new coffee();
coffee.secretaryMake();
}
三、注意事项
- 迪米特法则的核心是降低类之间的耦合
- 但是要注意:由于每个类都减少了不必要的依赖,因此迪米特法则只是要求降低类间(对象间)耦合关系,并不是要求完全没有依赖关系。
7、合成复用
一、基本介绍
尽量使用合成/聚合的方式,而不是使用继承
违背原则代码
static class A {
public void method1(){
System.out.println("你调用了方法一");
}
public void method2(){
System.out.println("你调用了方法二");
}
}
// B类继承A
static class B extends A{
}
public static void main(String[] args) {
B b = new B();
b.method1();
b.method2();
}
使用继承方式,B类继承了A类之后,就可以使用了A类中的两个方法,这样耦合性较高,不推荐
符合原则代码
/**
* ---------------------------------组合方式---------------------------------------------
*/
static class B{
A a = new A();
public void method1(){
a.method1();
}
public void method2(){
a.method2();
}
}
public static void main(String[] args) {
B b = new B();
b.method2();
b.method1();
}
/**
* ---------------------------------依赖方式---------------------------------------------
*/
static class B{
public void method1(A a){
a.method1();
}
public void method2(A a){
a.method2();
}
}
组合/聚合的方式,在B类里注入A,通过注入的A类来调用方法,耦合性低,易扩展。符合合成复用的原则
依赖方式,把A类作为参数传递到B类的两个方法中,从而达到调用A类的方法,耦合性低。符合合成复用的原则
核心思想
- 1、找出应用中可能需要变化之处,把他们独立出来,不要和那些不需要变化的代码混在一起
- 2、针对接口编程,而不是针对实现编程
- 3、为了交互对象之间的松耦合设计而努力
相关文章
- 实践GoF的23种设计模式:SOLID原则(上)
- 软件开发除了23种设计模式,还有7个开发原则需要了解
- java设计模式--行为型模式--模板方法
- Spring-涉及到的设计模式汇总
- 设计模式三原则
- JAVA 设计模式 装饰者模式
- 设计模式六大原则【文章来源:新亮笔记-编程是一种思想,而不是敲代码】
- 【每天一个java设计模式(零)】 - 设计模式基本概念及七大设计原则
- 面向对象的设计模式之SOLID原则
- C#之设计模式之六大原则(转载)
- 学习设计模式六大设计原则之一
- 设计模式六大原则
- 设计模式:SOLID原则
- .NET(C#) 设计模式六大原则 单一职责原则
- 设计模式之三:观察者模式
- 设计模式笔记:开闭原则(OCP,The Open-Closed Principle)
- Groovy 设计模式 -- proxy & delegate
- PHP设计模式——策略模式
- 浅谈设计模式-合成复用原则
- 浅谈设计模式-里氏替换原则
- 浅谈设计模式-单一职责原则
- 大战设计模式(第二季)【5】———— 从源码看适配器模式
- [Unity 设计模式]IOC依赖倒置