设计模式的目的
编写软件过程中,程序员面临着来自耦合性,内聚性以及可维护性,可扩展性,重用性,灵活性等多方面的挑战,设计模式是为了让程序(软件),具有更好
1)代码重用性(即:相同功能的代码,不用多次编写)
2)可读性(变成的规范性,便于其他程序员的阅读)
3)可扩展性(当需要增加新功能时,非常方便,或叫可维护性)
4)可靠性(当我们增加新的功能后,对原有的功能没有影响)
5)使程序呈现高内聚,低耦合的特性
分析金句:
设计模式包含了面向对象的精髓,“懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要”
Scott Mavers 在其巨著《Effective C++》就曾经说过:C++老手和C++新手的区别就是前者手背上有很多伤疤
设计模式的七大原则
设计模式原则,其实就是程序员在编程时,应当遵守的原则,也是各种设计模式的基础(即:设计模式为什么这样设计的依据)
设计模式常用的七大原则有:
1)单一职责原则
2)接口隔离原则
3)依赖倒转(倒置)原则
4)里氏替换原则
5)开闭原则
6)迪米特法则T7)合成复用原则
单一职责原则
基本介绍
对类来说的,即一个类应该只负责一项职责。如类A负责两个不同职责:职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2
应用实例
1)以交通工具案例讲解
2)看老师代码演示
3)方案1[分析说明]
4)方案2[分析说明]
5)方案3[分析说明]
单一职责原则注意事项和细节
1)降低类的复杂度,一个类只负责一项职责。
2)提高类的可读性,可维护性
3)降低变更引起的风险
4)通常情况下,我们应当遵守单一职责原则,只有逻辑足够简单,才可以在代码级违反单一职责原则;只有类中方法数量足够少,可以在方法级别保持单一职责原则
接口隔离原则(Interface Segregation Principle)
基本介绍
1)客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上
代码解释
interface interface1 {void method1();void method2();void method3();void method4();void method5();}class classB implements interface1 {@Overridepublic void method1() {System.out.println("B -- method1");}@Overridepublic void method2() {System.out.println("B -- method2");}@Overridepublic void method3() {System.out.println("B -- method3");}@Overridepublic void method4() {System.out.println("B -- method4");}@Overridepublic void method5() {System.out.println("B -- method5");}}class classA {public void test1(interface1 classB) {classB.method1();classB.method2();classB.method3();}}class classD implements interface1 {@Overridepublic void method1() {System.out.println("D -- method1");}@Overridepublic void method2() {System.out.println("D -- method2");}@Overridepublic void method3() {System.out.println("D -- method3");}@Overridepublic void method4() {System.out.println("D -- method4");}@Overridepublic void method5() {System.out.println("D -- method5");}}class classC {public void test1(interface1 classD) {classD.method1();classD.method4();classD.method5();}}
我们可以看到:
类B实现了 接口interface1,
类A 依赖类B,但只用到了类B中的方法:method1、method2、method3 ,其他两个方法没用到
这就不满足接口隔离原则,所以应该将 interface1 划分为最小
按隔离原则应当这样处理:
将接口Interface1拆分为独立的几个接口,类A和类c分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则
应传统方法的问题和使用接口隔离原则改进
1、我们将interface1,划分为3个接口:
interfaceA 包含 method1
interfaceB 包含 method2、method3
interfaceC 包含 method4、method5
类B实现interfaceA 、interfaceB
类D实现interfaceA 、interfaceC
类A再依赖类B的时候(类C依赖类D的时候) 就遵循接口隔离原则
依赖倒置原则
基本介绍
依赖倒转原则(Dependence Inversion Principle)是指:
1)高层模块不应该依赖低层模块,二者都应该依赖其抽象
- 例1
- dao层不依赖service层
- 例2
- dao层的实现类依赖dao层的接口
- service层的实现类依赖service层的接口
2)抽象不应该依赖细节,细节应该依赖抽象
3)依赖倒转(倒置)的中心思想是面向接口编程
4)依赖倒转原则是基于这样的设计理念:相对于细节的多变性,抽象的东西要稳定的多。以抽象为基础搭建的架构比以细节为基础的架构要稳定的多。在java中,抽象指的是接口或抽象类,细节就是具体的实现类
5)使用接口或抽象类的目的是制定好规范,而不涉及任何具体的操作,把展现细节的任务交给他们的实现类去完成
里氏替换原则
oop中的继承性的思考和说明
1)继承包含这样一层含义:父类中凡是已经实现好的方法,实际上是在设定规范和契约,虽然它不强制要求所有的子类必须遵循这些契约,但是如果子类对这些已经实现的方法任意修改,就会对整个继承体系造成破坏。
2)继承在给程序设计带来便利的同时,也带来了弊端。比如使用继承会给程序带来侵入性,程序的可移植性降低,增加对象间的耦合性,如果一个类被其他的类所继承,则当这个类需要修改时,必须考虑到所有的子类,并且父类修改后,所有涉及到子类的功能都有可能产生故障
3)问题提出:在编程中,如何正确的使用继承?=>里氏替换原则
基本介绍
1)里氏替换原则(Liskov Substitution Principle)在1988年,由麻省理工学院的以为姓里的女士提出的。
2)如果对每个类型为T1的对象O1,都有类型为T2的对象O2,使得以T1定义的所有程序P在所有的对象O1都代换成O2时,程序P的行为没有发生变化,那么类型T2是类型T1的子类型。换句话说,所有引用基类的地方必须能透明地使用其子类的对象。
3)在使用继承时,遵循里氏替换原则,在子类中尽量不要重写父类的方法
4)里氏替换原则告诉我们,继承实际上让两个类耦合性增强了,在适当的情况下,可以通过聚合,组合,依赖来解决问题。.
开闭原则
基本介绍
1)开闭原则(Open Closed Principle)是编程中最基础、最重要的设计原则
2)一个软件实体如类,模块和函数应该对扩展开放(对提供方),对修改关闭(对使用方)。用抽象构建框架,用实现扩展细节。
3)当软件需要变化时,尽量通过扩展软件实体的行为来实现变化,而不是通过修改已有的代码来实现变化。
- 因为原来已有的代码,可能被其他类所使用,如果我们直接修改原来的代码,可能造成其他功能的失效!
4)编程中遵循其它原则,以及使用设计模式的目的就是遵循开闭原则。
迪米特法则
基本介绍
1)一个对象应该对其他对象保持最少的了解
2)类与类关系越密切,耦合度越大
3)迪米特法则(Demeter Principle)又叫最少知道原则,即一个类对自己依赖的类知道的越少越好。也就是说,对于被依赖的类不管多么复杂,都尽量将逻辑封装在类的内部。对外除了提供的public 方法,不对外泄露任何信息
4)迪米特法则还有个更简单的定义:只与直接的朋友通信
- 直接的朋友:每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。
合成复用原则
基本介绍
原则是尽量使用合成/聚合的方式,而不是使用继承
设计原则的总结
1)找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起。
2)针对接口编程,而不是针对实现编程。
3)为了交互对象之间的松耦合设计而努力
UML介绍
1)UML—Unified modeling language UML(统一建模语言),是一种用于软件系统分析和设计的语言工具,它用于帮助软件开发人员进行思考和记录思路的结果
2)UML本身是一套符号的规定,就像数学符号和化学符号一样,这些符号用于描述软件模型中的各个元素和他们之间的关系,比如类、接口、实现、泛化、依
赖、组合、聚合等,如右图:
3)使用UML来建模,常用的工具有Rational Rose,也可以使用一些插件来建模
uml图
画UML图与写文章差不多,都是把自己的思想描述给别人看,关键在于思路和条理,UML图分类:
1)用例图(use case)
2)静态结构图:类图、对象图、包图、组件图、部署图3)动态行为图:交互图(时序图与协作图)、状态图、活动图说明:
1)类图是描述类与类之间的关系的,是UML图中最核心的2)在讲解设计模式时:我们必然会使用类图,为了让学员们能够把设计模式学到位,需要先给大家讲解类图
3)温馨提示:如果已经掌握UML类图的学员,可以直接听设计模式的章节
1)用于描述系统中的类(对象)本身的组成和类(对象)之间的各种静态关系。
2)类之间的关系:依赖、泛化(继承)、实现、关联、聚合与组合
3)类图简单举例。
类之间的关系
类图-依赖关系(Dependecy)
介绍
只要是在类中用到了对方,那么他们之间就存在依赖关系。如果没有对方,连编绎都通过不了。
小结
1)类中用到了对方
2)如果是类的成员属性
3)如果是方法的返回类型
4)是方法接收的参数类型
5)方法中使用到
类图-继承关系(Generalization)
介绍
泛化关系实际上就是继承关系,他是依赖关系的特例
类图-实现关系(Realization)
介绍
实现关系实际上就是A类实现B类,他是依赖关系的特例
类图-关联关系()
介绍
关联关系实际上就是类与类之间的联系,他是依赖关系的特例
关联具有导航性:即双向关系或单向关系
关系具有多重性:如“1”(表示有且仅有一个),“0..”(表示0个或者多个),
“0,1”(表示0个或者一个),“n..m”(表示n到m个都可以),“m…*”(表示至少m个)。
举例
单向一对一关系
public class Person{private IDCard card;public class IDCard}
双向一对一关系
public class Person{private IDCard card;}class IDCard{private Person person}
类图-关联关系(Aggregatio)
介绍
聚合关系(Aggregation)表示的是整体和部分的关系,整体与部分可以分开。聚合关系是关联关系的特例,所以他具有关联的导航性与多重性。
类图-组合关系(Compostion)
介绍
组合关系:也是整体与部分的关系,但是整体与部分不可以分开。
public class Person{private IDCard card; //人没有身份证也行,人和身份证是聚合关系private Head head=new Head(); //人没有头就会死,人和头是组合关系}public class IDCard0{}public class Head{}
但是,具体是组合还是聚合,需要依据具体情况分析:
比如:如果在程序中Person实体中定义了对IDCard进行级联删除,即删除Person时连同IDCard一起删除,那么IDCard和Person就是组合了
设计模式
掌握设计模式的层次
1)第1层:刚开始学编程不久,听说过什么是设计模式2)第2层:有很长时间的编程经验,自己写了很多代码,其中用到了设计模式,但是自己却不知道
3)第3层:学习过了设计模式,发现自己已经在使用了,并且发现了一些新的模式挺好用的
4)第4层:阅读了很多别人写的源码和框架,在其中看到别人设计模式,并且能够领会设计模式的精妙和带来的好处。
5)第5层:代码写着写着,自己都没有意识到使用了设计模式,并且熟练的写了出来。
设计模式的介绍
1)设计模式是程序员在面对同类软件工程设计问题所总结出来的有用的经验,模式不是代码,而是某类问题的通用解决方案,设计模式(Design pattern)代表了最佳的实践。这些解决方案是众多软件开发人员经过相当长的一段时间的试验和错误总结出来的。
2)设计模式的本质提高软件的维护性,通用性和扩展性,并降低软件的复杂度。
3)<<设计模式>>是经典的书,作者是Erich Gamma、Richard Helm、Ralph Johnson 和John Vlissides Design(俗称“四人组GOF”)
4)设计模式并不局限于某种语言,java,php,c++都有设计模式.
设计模式类型
设计模式分为三种类型,共23种
1)创建型模式:单例模式、抽象工厂模式、原型模式、建造者模式、工厂模式。
2)结构型模式:适配器模式、桥接模式、装饰模式、组合模式、外观模式、享元模式、代理模式。
3)行为型模式:模版方法模式、命令模式、访问者模式、迭代器模式、观察者模式、中介者模式、备忘录模式、解释器模式(Interpreter模式)、状态模式、策略模式、职责链模式(责任链模式)。
注意:不同的书籍上对分类和名称略有差别
创建型模式
单例模式
介绍
所谓类的单例设计模式,就是采取一定的方法保证在整个的软件系统中,对某个类只能存在一个对象实例,并且该类只提供一个取得其对象实例的方法(静态方法)。
单例模式八种方式
1)饿汉式(静态常量)<如果确定其一定会使用,可以使用>
//饿汉式(静态变量)public class Hungry_staticConstant {private static final class Singleton{private Singleton(){}private final static Singleton instance=new Singleton();public static Singleton getInstance(){return instance;}}}//缺点:可能造成内存的浪费
2)饿汉式(静态代码块)<如果确定其一定会使用,可以使用>
public class Hungry_staticCodeBlock {private static class Singleton {private static Singleton instance;//在静态代码块执行时,创建单例对象static { instance = new Singleton(); }private Singleton() {}public static Singleton getInstance() {return instance;}}}//缺点:可能造成内存的浪费
3)懒汉式(线程不安全)<不推荐使用,线程不安全>
public class Lazy_threadUnsafe {private static class Singleton {private static Singleton singleton;private Singleton() {}//当调用getInstance才创建单例对象,饿汉式public static Singleton getInstance() {if (singleton == null) {singleton = new Singleton(); }return singleton;}}}//优点:有懒加载的效果//缺点:多线程下存在线程安全问题
4)懒汉式(线程安全,同步方法)<不推荐使用,效率低>
public class Lazy_threadSafe_SynchronizationMethod {private static class Singleton {private static Singleton singleton;private Singleton() { }//加入同步代码方法,解决线程不安全问题public static synchronized Singleton getInstance() {if (singleton == null) { singleton = new Singleton(); }return singleton;}}}//优点:懒加载+解决了线程安全问题//缺点:效率太低,每次调用获取实例方法,都得等待锁
5)懒汉式(线程安全,同步代码块)<不推荐使用,效率低>
//优点:懒加载+线程安全//缺点:效率低private static class Singleton {private static Singleton singleton;private Singleton() { }//加入同步代码方法,解决线程不安全问题public static Singleton getInstance() {synchronized (Singleton.class) {if (singleton == null) {singleton = new Singleton();}return singleton;}}}
6)双重检查<推荐使用>
//优点:懒加载+线程安全+效率private static class Singleton1 {private static Singleton1 singleton1;private Singleton1() { }//加入同步代码方法,解决线程不安全问题public static Singleton1 getInstance() {if (singleton1 == null) {synchronized (Singleton.class) {if (singleton1 == null) {singleton1 = new Singleton1();}}}return singleton1;}}
7)静态内部类<推荐使用>
//外部类装载的时候,静态内部类并不会去装载//优点:懒加载+线程安全(类的初始化是线程安全)+效率高public class Singleton{private Singleton(){}private static class SingletonInstance{private static final Singleton INSTANCE=new Singleton();}public static Singleton getInstance(){return SingletonInstance.INSTANCE;}}
8)枚举<推荐使用>
//线程安全+防止反序列化重新创建新的对象+被Java作者推荐使用public enum Singleton {INSTANCE;//业务方法1public void method1(){ }//业务方法2public void method2(){ }//...}class TestSingleton{public static void main(String[] args) {Singleton s1=Singleton.INSTANCE;Singleton s2=Singleton.INSTANCE;System.out.println(s1==s2); //true}}
JDK中使用到了单例设计模式
1)、java.lang.Runtime就是经典的单例设计模式(饿汉式)
单例模式注意事项和细节说明
单例模式注意事项和细节说时
1)单例模式保证了系统内存中该类只存在一个对象,节省了系统资源,对于一些需要频繁创建销毁的对象,使用单例模式可以提高系统性能
2)当想实例化一个单例类的时候,必须要记住使用相应的获取对象的方法,而不是使用new
3)单例模式使用的场景:需要频繁的进行创建和销毁的对象、创建对象时耗时过多或耗费资源过多(即:重量级对象),但又经常用到的对象、工具类对象、频繁访问数据库或文件的对象(比如数据源、session工厂等)
工厂设计模式
看一个具体的需求
看一个披萨的项目:要便于披萨种类的扩展,要便于维护
1)披萨的种类很多(比如GreekPizz、CheesePizz等)
2)披萨的制作有 prepare,bake,cut,box
3)完成披萨店订购功能。
类图
解释:
Pizza(披萨抽象类):
有方法:
1、prepare() 原材料的准备
2、bake() 烘烤
3、cut() 切块
4、box() 装箱
OrderPizza (订单类):
类中有方法:
if(“Cheese”.equals(pizza.getName)){
//创建Cheese对象并,进行 CheesePizza的制作
}else if(“Greek”.equals(pizza.getName)){
//创建Greek对象并,进行 GreekPizza的制作
}else if(“Pepper”.equals(pizza.getName)){
//创建Pepper对象并,进行 PepperPizza的制作 //当增加披萨种类,需要修改的源码
}else{
return;
}
CheesePizza (奶酪披萨) 继承Pizza
GreekPizza(希腊披萨)继承Pizza
出现的问题:
当我们出现新的 披萨种类,需要修改 OrderPizza方法,这就违反了我们的 OCP原则(开闭原则)。
并且 生产披萨的店不止一家,所以 需要修改多个OrderPizza类。
简单工厂模式(也叫静态工厂)
基本介绍
1)简单工厂模式是属于创建型模式,是工厂模式的一种。简单工厂模式是由一个工厂对象决定创建出哪一种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
2)简单工厂模式:定义了一个创建对象的类,由这个类来封装实例化对象的行为(代码)
3)在软件开发中,当我们会用到大量的创建某种、某类或者某批对象时,就会使用到工厂模式.
图示
解释:
OrderPizza (每个披萨商店不再自己 通过不同类型的披萨来自己 创建披萨对象),
而是 创Order建一个创建披萨对象的工厂,通过输入的类型,调用工厂来完成披萨对象的创建。
这样就不用 修改OrderPizza 类了,当增加披萨种类的时候,仅需对工厂操作就行了
工厂方法模式
看一个新的需求
披萨项目新的需求:客户在点披萨时,可以点不同口味的披萨,比如北京的奶酪pizza、北京的胡椒pizza或者是伦敦的奶酪pizza、伦敦的胡椒pizza。
思路1
使用简单工厂模式,创建不同的简单工厂类(需要创建很多简单工厂),比如BJPizzaSimpleFactory、LDPizzaSimpleFactory等等.从当前这个案例来说,也是可以的,但是考虑到项目的规模,以及软件的可维护性、可扩展性并不是特别好
思路2
使用工厂方法模式
工厂方法模式介绍
工厂方法模式设计方案:将披萨项目的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。工厂方法模式将对象的实例化推迟到子类。
图示
马士兵讲设计模式
工厂设计模式
1、任意扩展交通工具(非工厂设计模式)
//车辆的接口public interface Vehicle { void go();}//小汽车类public class Car implements Vehicle{@Overridepublic void go(){System.out.println("car go");}}//飞机类public class Plane implements Vehicle{@Overridepublic void go(){System.out.println("plane go");}}//调用类public class Main {public static void main(String[] args) {runVehicle(new Car());}public static void runVehicle(Vehicle vehicle){vehicle.go();}}
解说:
- 优点:我们可以在23行,new哪个交通工具,就让哪个交通工具运行。
并且,如果我们想扩展交通工具。只需要创建一个交通工具类实现Vehicle接口即可。
- 缺点:23行,假如我们在new Car()的时候需要设置很多的参数。比如:我们想要将Car的颜色,材料,等参数设置进Car。这时,第23行就要换成以下代码 :
Color c=new Color();
Material m=new Material();
runVehicle(new Car(c,m));
这时候,直接new对象的方式,显得非常麻烦。
怎么解决这个问题呢?
2、任意扩展交通工具(工厂设计模式/静态工厂模式)【方便扩展单个产品,但不能扩展一组产品】
//车辆的接口public interface Vehicle { void go();}//小汽车类public class Car implements Vehicle{@Overridepublic void go(){System.out.println("car go");}}//飞机类public class Plane implements Vehicle{@Overridepublic void go(){System.out.println("plane go");}}//交通工具工厂接口public interface Factory { Vehicle create();}//汽车工厂类public class CarFactory implements Factory {@Override public Car create() {return new Car();}}//飞机工厂类public class PlaneFactory implements Factory{@Overridepublic Plane create() {return new Plane();}}//调用者方法public class Main {public static void main(String[] args) {Vehicle vehicle = createVehicle(new PlaneFactory());vehicle.go();}public static Vehicle createVehicle(Factory factory){return factory.create();}}
解说:
- 优点:
1、当我们想要获得某一个具体的交通工具(如Car)的时候,我们只需要new CarFactory().create() 即可。我们可以在CarFactory中将颜色呀,材料呀 这些属性传递过去,就不用调用者手动设置 参数了。
2、我们也可以定制生产过程,只需要创建一个工厂类,然后实现工厂接口即可。假如说我们觉得CarFactory工厂落后了,我们可以创建一个 NewCarFactory,然后实现工厂接口。然后在41行,
new NewCarFactory() 接口。(符合开闭原则)
3、任意扩展一个世界(抽象工厂)【方便扩展一组产品,但不方便为每一组扩展一个产品】
标题解释:
方便扩展一组产品:
交通工具,武器
现实世界:(小轿车,AK47)
魔法世界:(飞行扫把,魔法)
当我们在扩展一个世界的时候:
仙侠世界:(御剑,气功)
这样的扩展是很方便的!
不方便扩展一个产品
但是,如果每个世界再添加一个 食物,即:
交通工具,武器 ,食物
这样是不能扩展的
实例代码如下:
//抽象世界public abstract class AbstractFactory {abstract VehicleFactory createVehicle();abstract WeaponFactory createWeapon();//如果我们想要扩展世界里面的东西,这里是不行的,还得修改抽象世界的抽象方法}// 具体的现实世界public class RealWorldFactory extends AbstractFactory {@OverrideVehicleFactory createVehicle() {return new CarFactory();}@OverrideWeaponFactory createWeapon() {return new AK47Factory();}}//具体的魔法世界public class MagicWorldFactory extends AbstractFactory {@OverrideVehicleFactory createVehicle() {return new BroomFactory();}@OverrideWeaponFactory createWeapon() {return new MagicFactory();}}//抽象 车辆工厂public abstract class VehicleFactory{abstract Vehicle create();}//抽象 武器工厂public abstract class WeaponFactory {abstract Weapon create();}//具体 Car工厂public class CarFactory extends VehicleFactory {@OverrideVehicle create() {return new Car();}}//具体的 AK47工厂public class AK47Factory extends WeaponFactory{@OverrideWeapon create() {return new AK47();}}//具体的扫把工厂public class BroomFactory extends VehicleFactory {@OverrideVehicle create() {return new Broom();}}//具体的魔法工厂public class MagicFactory extends WeaponFactory {@OverrideWeapon create() {return new Magic();}}//抽象的交通工具public abstract class Vehicle {abstract void go();}//抽象的武器public abstract class Weapon {abstract void shoot();}//具体的交通工具--Carpublic class Car extends Vehicle {@Overridepublic void go() {System.out.println("car go");}}//具体的武器--AK47public class AK47 extends Weapon{@Overridevoid shoot() {System.out.println("AK47 shoot");}}//具体的交通工具--扫把public class Broom extends Vehicle {@Overridevoid go() {System.out.println("Broom go");}}//具体的武器--魔法public class Magic extends Weapon {@Overridevoid shoot() {System.out.println("Magic shoot");}}//调用者public class Main {public static void main(String[] args) {RealWorldFactory realWorldFactory = new RealWorldFactory();VehicleFactory vehicle = realWorldFactory.createVehicle();vehicle.create().go();WeaponFactory weapon = realWorldFactory.createWeapon();weapon.create().shoot();}}
3、任意扩展一个世界和产品(抽象工厂)【方便扩展一个世界,也可以为每个世界扩展一个产品】
//旧的抽象世界 --产品少public abstract class WorldFactory {abstract VehicleFactory createVehicle();abstract WeaponFactory createWeapon();}//旧的真实世界--产品少public class RealWorldFactory extends WorldFactory {@OverrideVehicleFactory createVehicle() {return new CarFactory();}@OverrideWeaponFactory createWeapon() {return new AK47Factory();}}//新的抽象世界 --产品多public abstract class ExtendWorldFactory {abstract VehicleFactory createVehicle();abstract WeaponFactory createWeapon();abstract FoodFactory createFood();}//新的真实世界 --产品多public class ExtendRealWorldFactory extends ExtendWorldFactory{@OverrideVehicleFactory createVehicle() {return new CarFactory();}@OverrideWeaponFactory createWeapon() {return new AK47Factory();}@OverrideFoodFactory createFood() {return new RiceFactory();}}//抽象交通工具工厂public abstract class VehicleFactory{abstract Vehicle create();}//抽象武器工厂public abstract class WeaponFactory {abstract Weapon create();}//抽象食物工厂public abstract class FoodFactory {abstract Food create();}//具体Car 工厂public class CarFactory extends VehicleFactory {@OverrideVehicle create() {return new Car();}}//具体武器Ak47工厂public class AK47Factory extends WeaponFactory {@OverrideWeapon create() {return new AK47();}}//具体食物米饭工厂public class RiceFactory extends FoodFactory {@OverrideFood create() {return new Rice();}}//抽象交通工具public abstract class Vehicle {abstract void go();}//抽象武器实体类public abstract class Weapon {abstract void shoot();}//抽象食物类public abstract class Food {abstract void eat();}//具体交通工具carpublic class Car extends Vehicle {@Overridepublic void go() {System.out.println("car go");}}//具体武器Ak47public class AK47 extends Weapon {@Overridevoid shoot() {System.out.println("AK47 shoot");}}//具体食物米饭public class Rice extends Food {@Overridevoid eat() {System.out.println("eat Rice");}}//测试类public class Main {public static void main(String[] args) {System.out.println("-------------旧世界----------------");//旧世界中(真实世界)行为OldWorldActive(new RealWorldFactory());System.out.println("-------------扩展世界----------------");//扩展世界中(真实世界)行为extendWorldActive(new ExtendRealWorldFactory());}public static void OldWorldActive(WorldFactory worldFactory){VehicleFactory vehicle = worldFactory.createVehicle();WeaponFactory weapon = worldFactory.createWeapon();vehicle.create().go();weapon.create().shoot();}public static void extendWorldActive(ExtendWorldFactory extendWorldFactory){VehicleFactory vehicle = extendWorldFactory.createVehicle();WeaponFactory weapon = extendWorldFactory.createWeapon();FoodFactory food = extendWorldFactory.createFood();vehicle.create().go();weapon.create().shoot();food.create().eat();}}
总结:以上都是符合OCP开闭原则,即:对修改关闭,对扩展开放
构建者设计模式
定义
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
主要作用
在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。
代码解释
//【1】具体要生成的对象public class Product {private String foundation;private String wall;private String roof;public String getFoundation() {return foundation;}public Product setFoundation(String foundation) {this.foundation = foundation;return this;}public String getWall() {return wall;}public Product setWall(String wall) {this.wall = wall;return this;}public String getRoof() {return roof;}public Product setRoof(String roof) {this.roof = roof;return this;}@Overridepublic String toString() {return "Product{" +"foundation='" + foundation + '\'' +", wall='" + wall + '\'' +", roof='" + roof + '\'' +'}';}}//【2】抽象构建者public abstract class Builder {abstract void buildFoundation();abstract void buildWall();abstract void buildRoof();abstract Product getProduct();}//【4-1】具体的构建者 低级工人public class Low_Worker extends Builder {private Product product;public Low_Worker() { this.product = new Product(); }@Overridevoid buildFoundation() { product.setFoundation("打地基"); }@Overridevoid buildWall() { product.setWall("刷墙"); }@Overridevoid buildRoof() { product.setRoof("修房顶"); }@OverrideProduct getProduct() { return product; }}//【4-2】具体的构建者 中级工人public class Low_Worker extends Builder {private Product product;public Low_Worker() { this.product = new Product(); }@Overridevoid buildFoundation() { product.setFoundation("打牛逼地基"); }@Overridevoid buildWall() { product.setWall("刷牛逼的墙"); }@Overridevoid buildRoof() { product.setRoof("修牛逼的房顶"); }@OverrideProduct getProduct() { return product; }}//【5】我们需要一个包工头 指挥不同工人,按照一定的业务流程进行//可以扩展 不同的设计者public class Designer {public Product build(Builder builder){//1、先建地基builder.buildFoundation();//2、再墙壁builder.buildWall();//3、最后房顶builder.buildRoof();return builder.getProduct();}}//【6】客户调用public class Main {public static void main(String[] args) {//包工头Designer designer = new Designer();//包工作让 具体的工人干活 我们传递低级工人,产生低级产品,//让中级工人干活,产生中级产品Product product1 = designer.build(new Mid_Worker());System.out.println(product1);}}
原型模式
原型(prototype)对应于我们Spring中的Bean的多例模式
原型模式是对对象的拷贝
代码实例
public class Video implements Cloneable{private String videoName;private Date videoTime;//浅拷贝----它们的 videoTime 引用变量指向的是同一个 堆空间的地址@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone();}//深拷贝 -- 将他的属性 也拷贝@Overrideprotected Object clone() throws CloneNotSupportedException {Video video = (Video) super.clone();Date videoTime = video.getVideoTime();Date cloneVideoTime = (Date) videoTime.clone();video.setVideoTime(cloneVideoTime);return video;}@Overridepublic String toString() {return "Video{" +"videoName='" + videoName + '\'' +", videoTime=" + videoTime +'}';}public String getVideoName() { return videoName; }public void setVideoName(String videoName) { this.videoName = videoName; }public Date getVideoTime() { return videoTime; }public void setVideoTime(Date videoTime) { this.videoTime = videoTime; }}//【测试】public class Main {public static void main(String[] args) throws CloneNotSupportedException {Video video = new Video();video.setVideoName("狂神Java");video.setVideoTime(new Date());Video cloneVideo = (Video) video.clone();System.out.println("video=>"+video);System.out.println("cloneVideo=>"+cloneVideo);System.out.println(video.getVideoTime()==cloneVideo.getVideoTime());}}
结构型模式
作用:
从程序的结构上实现耦合,从而可以扩大整体的类结构,用来解决更大的问题
适配器模式

代码演示:
假如该电脑,没有网线接口,只有USB接口,需要适配器来连接网线
【1】适配器模式1,类适配器
//网线public class Network {public void onNet(){System.out.println("开始上网");}}//适配器接口public interface NetToUsb {void netPlay();}//具体的适配器public class ClassAdapter extends Network implements NetToUsb{//该适配器继承网线,假如来一个新的网线,适配器并不能适配其他网线,//这种类适配器的方式是有弊端的@Overridepublic void netPlay() {super.onNet();}}//电脑public class Computer {public void onNet(NetToUsb adaptor){ //电脑需要上网,必须有适配器adaptor.netPlay();}}//测试类public class Main {public static void main(String[] args) {Computer computer = new Computer();//电脑ClassAdapter classAdapter = new ClassAdapter();//适配器computer.onNet(classAdapter);//电脑通过适配器才能上网}}
【2】适配器模式2,对象适配器
//网线public class Computer {public void onNet(NetToUsb adaptor){adaptor.netPlay();}}//适配器接口public interface NetToUsb {void netPlay();}//具体的适配器public class ObjectAdapter implements NetToUsb{//组合的方式private Network network;//我们可以创建一个网线的接口(NewWorkInterface),让不同的网线继承他,// 这个构造器的形参就可以改为 (NewWorkInterface nwi)//这样以便于我们日后更换网线,传入不同的具体网线对象public ObjectAdapter(Network network) {this.network = network;}@Overridepublic void netPlay() {network.onNet();}}//电脑public class Computer {public void onNet(NetToUsb adaptor){adaptor.netPlay();}}//测试类public class Main {public static void main(String[] args) {Computer computer = new Computer();//电脑Network network = new Network();//网线ObjectAdapter adapter = new ObjectAdapter(network);//适配器computer.onNet(adapter);}}
桥接模式
问题的引入
我们想要扩展华为品牌,需要扩展华为的台式机,华为笔记本,华为平板,需要增加三个类
我们想要扩展一个手表,也要为每一个品牌创建一个手表类,这就违反了单一职责原则。
那我们应该怎么简化呢?
桥接模式
代码演示
//品牌接口public interface Brand {String info();}//苹果品牌public class Apple implements Brand{@Overridepublic String info() {return "苹果";}}//联想品牌public class Lenovo implements Brand{@Overridepublic String info() {return "联想";}}public abstract class Computer {//品牌作为电脑的属性,组合进电脑protected Brand brand;public Computer(Brand brand) {this.brand = brand;}abstract void info();}class Desktop extends Computer{public Desktop(Brand brand) {super(brand);}@Overridevoid info() {System.out.println(brand.info()+"台式电脑");}}class NotBook extends Computer{public NotBook(Brand brand) {super(brand);}@Overridevoid info() {System.out.println(brand.info()+"笔记本电脑");}}//测试public class Main {public static void main(String[] args) {//需要哪个品牌的 什么之间new 就行Desktop desktop = new Desktop(new Apple());desktop.info();NotBook notBook = new NotBook(new Lenovo());notBook.info();}}
好处:如果我们想要增加一个品牌或者一种电脑,只需要增加一个具体的品牌或一个具体的电脑就行。
中间有一个桥相连。桥的两边均符合单一职责原则
门面模式(又叫外观模式)
门面模式
图示:
当我们完成某个功能,需要调用这么多的模块,调用起来非常麻烦。
这时候我们需要一个门面,去帮我们调用,我们仅需要调用门面即可。
调停者模式(又叫中介模式)
调停者模式
图示
有五个功能模块,互相之间有复杂的调用关系,当我们新添加一个模块的时候,新的模块也需要调用旧的模块。
相互之间就显得非常的复杂。
所以:
我们每个功能模块相互之间不再调用,而是都和一个调停者打交道即可。
SpringMVC使用的就是这个:DispatcherServlet就是那个中介。
责任链模式
问题:
在论坛发表文章
后台要经过信息处理才可以发表或者进入数据库
测试代码1:
import java.util.ArrayList;import java.util.List;/*** 需求2:* 在 每一个filter中 都要判断是否 还需要继续进行filter*/public class Main {public static void main(String[] args) {Msg msg = new Msg();msg.setMsg("大家好:),<script>,欢迎访问 mashibing.com ,大家都是996");//过滤器链1FilterChain filterChain = new FilterChain();filterChain.add(new HTMLFilter()).add(new SensitiveFilter());//过滤器链2FilterChain filterChain1 = new FilterChain();filterChain1.add(new URLFilter()).add(new FaceFilter());//因为过滤器链实现了Filter接口,所以,也可以将filterChain1添加到filterChain中filterChain.add(filterChain1);//调用过滤器链的过来方法filterChain.doFilter(msg);System.out.println(msg);}}class Msg {String name;String msg;public String getMsg() {return msg;}public void setMsg(String msg) {this.msg = msg;}@Overridepublic String toString() {return "Msg{" +"msg='" + msg + '\'' +'}';}}interface Filter {boolean doFilter(Msg m); //只要其中一个过滤器返回false,或许的过滤器将不起作用}class HTMLFilter implements Filter {@Overridepublic boolean doFilter(Msg m) {String r = m.getMsg();r = r.replace("<", "[");r = r.replace(">", "]");m.setMsg(r);return true;}}class SensitiveFilter implements Filter {@Overridepublic boolean doFilter(Msg m) {String r = m.getMsg();r = r.replace("996", "955");m.setMsg(r);return true;}}class FaceFilter implements Filter {@Overridepublic boolean doFilter(Msg m) {String r = m.getMsg();r = r.replace(":)", "^V^");m.setMsg(r);return true;}}class URLFilter implements Filter {@Overridepublic boolean doFilter(Msg m) {String r = m.getMsg();r=r.replace("mashibing.com", "https://www.mashibing.com");m.setMsg(r);return true;}}class FilterChain implements Filter {List<Filter> filters = new ArrayList<>();public FilterChain add(Filter f) {filters.add(f);return this;}public boolean doFilter(Msg m) {for (Filter f : filters) {//如果链条上有一个过滤器为false,就返回falseif (!f.doFilter(m)) return false;}return true;}}
测试代码2:模拟JavaWeb中的过滤器链
/*** 需求3:* 就像JavaWeb中的过滤器那样,在进Servlet之前进过滤器链,响应回来的时候逆序执行过滤器* 执行的顺序为 request: filter1 --> filter2 -->filter3 --> Servlet* ↓* response: filter1 <-- filter2 <-- filter3*/public class FilterMain {public static void main(String[] args) {Request request = new Request();request.str = "大家好:),<script>,欢迎访问 mashibing.com ,大家都是996";FilterChain filterChain = new FilterChain();filterChain.add(new HTMLFilter()).add(new SensitiveFilter());Response response = new Response();response.str = "";filterChain.doFilter(request, response, filterChain);System.out.println(request.str);System.out.println(response.str);}}interface Filter {boolean doFilter(Request request, Response response, FilterChain filterChain);}class Request {String str;}class Response {String str;}class HTMLFilter implements Filter {@Overridepublic boolean doFilter(Request request, Response response, FilterChain filterChain) {request.str = request.str.replaceAll("<", "[").replaceAll(">", "]");filterChain.doFilter(request, response, filterChain);response.str += "响应-HTMLFilter";return true;}}class SensitiveFilter implements Filter {@Overridepublic boolean doFilter(Request request, Response response, FilterChain filterChain) {request.str = request.str.replaceAll("996", "922");filterChain.doFilter(request, response, filterChain);response.str += "响应-SensitiveFilter";return true;}}class FilterChain implements Filter {List<Filter> filters = new ArrayList<>();int index = 0;public FilterChain add(Filter f) {filters.add(f);return this;}public boolean doFilter(Request request, Response response, FilterChain filterChain) {if (index == filters.size()) return false;Filter f = filters.get(index);index++;return f.doFilter(request, response, this);}}
