软件设计模式(Software Design Pattern),又称设计模式,是一套被反复使用、多数人知晓的、经过分类编目的、代码设计经验的总结。它描述了在软件设计过程中的一些不断重复发生的问题,以及该问题的解决方案。
设计模式是软件设计中常见问题的典型解决方案。 每个模式就像一张蓝图, 你可以通过对其进行定制来解决代码中的特定设计问题。
对类来说的,即一个类应该只负责一项职责。
如类A负责两个不同职责:职责1,职责2。当职责1需求变更而改变A时,可能造成职责2执行错误,所以需要将类A的粒度分解为A1,A2
当客户端需要该对象的某一个职责时,不得不将其他不需要的职责全都包含进来,从而造成冗余代码或代码的浪费。
单一职责原则注意事项和细节
客户端不应该依赖它不需要的接口,即一个类对另一个类的依赖应该建立在最小的接口上。
将接口Interface 拆分为独立的几个接口, 让需要依赖的类分别与他们需要的接口建立依赖关系。也就是采用接口隔离原则
接口隔离原则时,应该根据以下几个规则来衡量。
类A通过接口Interface1依赖类B,类C通过接口Interface1依赖类D,如果接口
Interface1对于类A和类C来说不是最小接口,
那么类B和类D必须去实现他们不需要的方法。
接口隔离原则处理:
将接口Interface1拆分为独立的几个接口,
类A和类C分别与他们需要的接口建立依赖
关系。也就是采用接口隔离原则
依赖倒置原则的主要作用:
依赖关系传递的三种方式
接口传递
构造方法传递
setter方式传递
继承的弊端:
里氏替换原则:
核心:
在使用继承时,子类可以扩展父类的功能,但不能改变父类原有的功能,在子类中尽量不要重写父类的方法,如果迫不得已可以通过聚合,组合,依赖来解决问题
核心:对扩展开放(对提供方),对修改关闭(对使用方)
核心:一个类对自己依赖的类知道的越少越好;从依赖者的角度来说,只依赖应该依赖的对象。从被依赖者的角度说,只暴露应该暴露的方法。
直接的朋友:
每个对象都会与其他对象有耦合关系,只要两个对象之间有耦合关系,
我们就说这两个对象之间是朋友关系。耦合的方式很多,依赖,关联,组合,聚合等。其中,我们称出现成员变量,方法参数,方法返回值中的类为直接的朋友,
而出现在局部变量中的类不是直接的朋友。也就是说,陌生的类最好不要以局部变量的形式出现在类的内部。
迪米特法则注意事项和细节
原则是尽量使用合成/聚合的方式,而不是使用继承.如果要使用继承关系,则必须严格遵循里氏替换原则。合成复用原则同里氏替换原则相辅相成的,两者都是开闭原则的具体实现规范。
设计原则核心思想
UML 建模的核心是模型,模型是现实的简化、真实系统的抽象。UML 提供了系统的设计蓝图。当给软件系统建模时,需要采用通用的符号语言,这种描述模型所使用的语言被称为建模语言。在 UML 中,所有的描述由事物、关系和图这些构件组成。下图完整地描述了所有构件的关系。其中类图是其最重要的部分也是最常用的图
在UML类图中:
依赖、泛化(继承)、实现、关联、聚合与组合
只要是在类中用到了对方,那么他们之间就存在依赖关系。如果没有对方,连编绎都通过不了 以下5中情况都是依赖关系
泛化关系实际上就是继承关系,它是依赖关系的特例,表示一般与特殊的关系,是父类与子类之间的关系
实现关系实际上就是A类实现B接口,它是依赖关系的特例。在这种关系中,类实现了接口,类中的操作实现了接口中所声明的所有的抽象操作。
关联关系实际上就是类与类之间的联系,它是依赖关系的特例
聚合关系表示的是整体和部分的关系,代表整体与部分可以分开。聚合关系是关联关系的特例,所以他具有关联的导航性与多重性
也是整体与部分的关系,但是整体与部分不可以分开。
在IDEA中可以可以右键包然后选择Diagrams 选择类图,也可以使用快捷键crtl+alt+shift+u来显示类图,使用IDEA自带的需要先设计好程序后才能显示类图,即无法自己画类图,如果需要自己画类图则安装插件PlantUML Itegration
使用PlantUML Itegration 制作的建造者模式的UMl类图示例:具体使用规则参考 PlantUML Itegration插件 使用规则
如果是Eclipse 则可以使用 UML插件(AmaterasUML) 来制作类图
注意:
类图(三种类型(组合、聚合、关联)在IntelliJ IDEA均以实线+菱形箭头+普通箭头表示,菱形箭头指向整体,普通箭头指向部分,箭头两端的数字表示实例的个数
创建型模式,共五种:工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式。
结构型模式,共七种:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式。
行为型模式,共十一种:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式。
创建型模式:就是创建对象的模式,抽象了实例化的过程。它帮助一个系统独立于如何创建、组合和表示它的那些对象。关注的是对象的创建,创建型模式将创建对象的过程进行了抽象,也可以理解为将创建对象的过程进行了封装,作为客户程序仅仅需要去使用对象,而不再关心创建对象过程中的逻辑。
结构型模式:为解决怎样组装现有的类,设计他们的交互方式,从而达到实现一定的功能的目的。结构型模式包容了对很多问题的解决。例如:扩展性(外观、组成、代理、装饰)封装性(适配器,桥接)
行为型模式:涉及到算法和对象间职责的分配,行为模式描述了对象和类的模式,以及它们之间的通信模式,行为型模式刻划了在程序运行时难以跟踪的复杂的控制流
可分为行为类模式和行为对象模式
一些行为对象模式描述了一组对等的对象怎样相互协作以完成其中任何一个对象都无法单独完成的任务。
根据模式是主要用于类上还是主要用于对象上来分,这种方式可分为类模式和对象模式两种。
类模式:用于处理类与子类之间的关系,这些关系通过继承来建立,是静态的,在编译时刻便确定下来了。GoF中的工厂方法、(类)适配器、模板方法、解释器属于该模式。
对象模式:用于处理对象之间的关系,这些关系可以通过组合或聚合来实现,在运行时刻是可以变化的,更具动态性。GoF 中除了以上 4 种,其他的都是对象模式。
单例模式
原型模式(Prototype模式)是指:用原型实例指定创建对象的种类,并且通过拷贝这些原型,创建新的对象
原型模式是一种创建型设计模式,允许一个对象再创建另外一个可定制的对象,无需知道如何创建的细节
概括:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例
工作原理 :通过将一个原型对象传给那个要发动创建的对象,这个要发动创建的对象通过请求原型对象拷贝它们自己来实施创建,即对象.clone();
主要角色:
浅拷贝就是只拷贝了对象的基本类型值和引用值,但被复制的对象引用类型的属性仍然指向原来的对象。说白了拷贝对象仅仅拷贝了原对象属性值的一个引用,此引用仍然指向相同的地址
String 除外 ,实现Cloneable 覆写Clone 方法 这个就是浅拷贝
String的内容保存在常量池中,所以对其做修改只是改变了成员变量所引用的常量池的串,不会影响其它拷贝对象中的该成员
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address = "蒙古羊";
public Sheep friend; //是对象, 克隆是会如何处理
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
}
//克隆该实例,使用默认的clone方法来完成
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
就是对所有的属性都独立地复制一份。对于基本类型属性即是复制一份值(成员变量自会提供独立的空间),而对于引用类型的属性就是重新建立了一个一模一样的对象,引用值不再相同(不再指向同一个对象)
实现Cloneable 一层一层覆写Clone 方法 也可以实现深度拷贝
如果想实现引用数据的类型的属性也是引用类型的对象拷贝,则需要使用深度拷贝
直接使用Java的clone()可以实现深拷贝,
使用序列化实现深拷贝是一种好的方式,也可以考虑使用一些其它工具,如Spring的BeanUtils工具
public class Sheep implements Cloneable {
private String name;
private int age;
private String color;
private String address = "蒙古羊";
public Sheep friend; //是对象, 克隆是会如何处理
public Sheep(String name, int age, String color) {
super();
this.name = name;
this.age = age;
this.color = color;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getColor() {
return color;
}
public void setColor(String color) {
this.color = color;
}
public void setFriend(Sheep friend) {
this.friend = friend;
}
public Sheep getFriend() {
return friend;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", age=" + age + ", color=" + color + ", address=" + address + "]";
}
//克隆该实例,使用默认的clone方法来完成--对象的深拷贝
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep clone = (Sheep)super.clone();
if (friend != null) {
clone.friend = (Sheep) clone.friend.clone();
}
else clone.friend = (Sheep) super.clone();
return clone;
}
}
建造者模式(Builder Pattern )又叫生成器模式,是一种对象构建模式。它可以将复杂对象的建造过程抽象出来(抽象类别),使这个抽象过程的不同实现方法可以构造出不同表现(属性)的对象。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。
概括:将一个复杂对象分解成多个相对简单的部分,然后根据不同需要分别创建它们,最后构建成该复杂对象
核心:将产品和产品建造过程解耦;对对象创建进行组装,如果产品之间的差异性很大,则不适合使用建造者模式。
优点:
缺点 :
使用建造者模式模拟构建房屋
public abstract class HorseAbsBuilder {
protected Horse horse = new Horse();
protected abstract void buildFoundation();
protected abstract void buildWall();
protected abstract void buildRoofed();
public void horseBuilder(){
buildFoundation();
buildWall();
buildRoofed();
}
public Horse horseBuilderFinished() {
return horse;
}
}
public class HorseDirector {
private HorseAbsBuilder builder;
public HorseDirector( ) { }
public void setHouseBuilder(HorseAbsBuilder builder) {
this.builder = builder;
}
public Horse horseDirector(){
builder.horseBuilder();
return builder.horseBuilderFinished();
}
}
public class CommonHorseConcreteBuilder extends HorseAbsBuilder{
@Override
protected void buildFoundation() {
System.out.println("给普通房子建造地基");
}
@Override
protected void buildWall() {
System.out.println("给普通房子砌墙");
}
@Override
protected void buildRoofed() {
System.out.println("给普通房子封顶");
}
}
public class Horse {
private String foundation;
private String wall;
private String roofed;
public String getFoundation() {
return foundation;
}
public void setFoundation(String foundation) {
this.foundation = foundation;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoofed() {
return roofed;
}
public void setRoofed(String roofed) {
this.roofed = roofed;
}
public class BuildClient {
public static void main(String[] args) {
HorseAbsBuilder comHorseBuilder = new CommonHorseConcreteBuilder();
HorseAbsBuilder villaHorseBuilder = new villaHorseConcreteBuilder();
HorseDirector dir = new HorseDirector( );
dir.setHouseBuilder(comHorseBuilder);
System.out.println("普通房子"+dir.horseDirector());
dir.setHouseBuilder(villaHorseBuilder);
System.out.println("别墅房子"+dir.horseDirector());
}
}
}
定义一个创建产品对象的工厂接口,将产品对象的实际创建工作推迟到具体子工厂类当中。这满足创建型模式中所要求的“创建与使用相分离”的特点。
凡是需要生成复杂对象的地方,都可以尝试考虑使用工厂模式来代替
简单工厂模式是属于创建型模式,是工厂模式的一种。 简单工厂模式是由一个工厂对象决定创建出哪一 种产品类的实例。简单工厂模式是工厂模式家族中最简单实用的模式
简单工厂模式:定义了一个创建对象的类,由这个类来 封装实例化对象的行为(代码)
使用简单工厂生产USB接口
public class SimpleFactory {
public static USBInterface create(String type) {
switch (type) {
case "Flash" -> {
return new Flash();
}
case "Printers" -> {
return new Printers();
}
default -> {
return new Flash();
}
}
}
}
public class Flash implements USBInterface {
@Override
public void start() {
System.out.println("U盘开始传输数据");
}
@Override
public void stop() {
System.out.println("U盘被拔出");
}
}
public class Printers implements USBInterface{
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机停止工作");
}
}
public class Order {
String orderType;
public Order(String orderType) {
this.orderType = orderType;
}
public void getUSB() {
USBInterface usbInterface = SimpleFactory.create(orderType);
usbInterface.start();
usbInterface.stop();
}
}
interface USBInterface {
void start();
void stop();
}
public class SimpleFactoryModeTest{
//简单工厂模式(静态工厂模式)--简单--可扩展性低,不满足 开闭原则OCP“对扩展开发,对修改关闭”原则
public static void main(String[] args) {
Order order = new Order("Flash");
order.getUSB();
Order order1 = new Order("Printers");
order1.getUSB();
}
}
优点
缺点
对于产品种类相对较少的情况,考虑使用简单工厂模式。使用简单工厂模式的客户端只需要传入工厂类的参数,不需要关心如何创建对象的逻辑,可以很方便地创建所需产品。
工厂方法模式设计方案:将对象的实例化功能抽象成抽象方法,在不同的口味点餐子类中具体实现。
工厂方法模式:定义了一个创建对象的抽象方法,由子类决定要实例化的类。
核心:定义一个抽象方法,让各个工厂子类自己实现。工厂方法模式将对象的实例化推迟到子类
当需要生成的产品不多且不会增加,一个具体工厂类就可以完成任务时,可删除抽象工厂类。这时工厂方法模式将退化到简单工厂模式
使用工厂方法模式生产USB接口:手机usb接口;电脑USB接口
分别对应打印机,u盘
public class ComputerUSB extends OrderUsb{
public ComputerUSB(String orderType) {
super(orderType);
}
@Override
public USBInterface getUSB() {
System.out.println("电脑USB接口");
return UsbFactory.create(orderType);
}
}
//这里的ComputerUSB PhoneUSB都是具体的工厂
public class FactoryMethodTest {
public static void main(String[] args) {
ComputerUSB orderUsb = new ComputerUSB("Printers");
USBInterface usb = orderUsb.getUSB();
usb.start();
usb.stop();
PhoneUSB orderUsb1 = new PhoneUSB("Flash");
USBInterface usb1 = orderUsb1.getUSB();
usb1.start();
usb1.stop();
}
}
public class Flash implements USBInterface {
@Override
public void start() {
System.out.println("U盘开始传输数据");
}
@Override
public void stop() {
System.out.println("U盘被拔出");
}
}
public abstract class OrderUsb {
String orderType;
public OrderUsb(String orderType) {
this.orderType = orderType;
}
public abstract USBInterface getUSB();
}
public class PhoneUSB extends OrderUsb {
public PhoneUSB(String orderType) {
super(orderType);
}
@Override
public USBInterface getUSB() {
System.out.println("手机USB接口");
return UsbFactory.create(orderType);
}
}
public class Printers implements USBInterface {
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机停止工作");
}
}
public class UsbFactory {
public static USBInterface create(String type) {
return switch (type) {
case "Flash" -> new Flash();
case "Printers" -> new Printers();
default -> new Flash();
};
}
}
interface USBInterface {
void start();
void stop();
}
抽象工厂模式:定义了一个interface用于创建相关或有依赖关系的对象簇,而无需指明具体的类
抽象工厂模式可以将简单工厂模式和工厂方法模式进行整合。
从设计层面看,抽象工厂模式就是对简单工厂模式的改进(或者称为进一步的抽象)。
将工厂抽象成两层,AbsFactory(抽象工厂)和具体实现的工厂子类。程序员可以根据创建对象类型使用对应的工厂子类。这样将单个的简单工厂类变成了工厂簇,更利于代码的维护和扩展。
概括:提供一个创建产品族的接口,其每个子类可以生产一系列相关的产品。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
区别在于产品,如果产品单一,最合适用工厂模式,但是如果有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种非常好的解决方式。再通俗深化理解下:工厂模式针对的是一个产品等级结构 ,抽象工厂模式针对的是面向多个产品等级结构的。
抽象工厂模式实现对产品家族的创建,一个产品家族是这样的一系列产品:具有不同分类维度的产品组合,采用抽象工厂模式不需要关心构建过程,只关心什么产品由什么工厂生产即可。
而建造者模式则是要求按照指定的蓝图建造产品,它的主要目的是通过组装零配件而产生一个新产品
使用抽象工厂模式改写USB接口生产,加入生产地伦敦和纽约
public class AbstractFactoryTest {
//1.产品接口--2工厂接口(抽象工厂)--3具体工厂--4产品
public static void main(String[] args) {
CreateFactory londonUSBFactory = new LondonUSBFactory();
ComputerUSB orderUsb = new ComputerUSB(londonUSBFactory);
orderUsb.getUSB("Flash");
CreateFactory newYorkUSBFactory = new NewYorkUSBFactory();
PhoneUSB phoneUSB = new PhoneUSB(newYorkUSBFactory);
phoneUSB.getUSB("Printers");
}
}
public class ComputerUSB extends OrderUsb {
public ComputerUSB(CreateFactory factory) {
super(factory);
}
@Override
public void getUSB(String type) {
USBInterface usbInterface = factory.USBFactory(type);
System.out.println("的电脑USB接口");
usbInterface.start();
usbInterface.stop();
}
}
public interface CreateFactory {
USBInterface USBFactory(String type);
}
public class Flash implements USBInterface {
@Override
public void start() {
System.out.println("U盘开始传输数据");
}
@Override
public void stop() {
System.out.println("U盘被拔出");
}
}
public class LondonUSBFactory implements CreateFactory {
@Override
public USBInterface USBFactory(String type) { //伦敦工厂生产对应的USB
System.out.println("伦敦USB工厂生产:");
return UsbFactory.create(type);
}
}
public class NewYorkUSBFactory implements CreateFactory{
@Override
public USBInterface USBFactory(String type) {
System.out.println("纽约USB工厂生产:");
return UsbFactory.create(type);
}
}
public abstract class OrderUsb {
CreateFactory factory;
public OrderUsb(CreateFactory factory) {
this.factory = factory;
}
public abstract void getUSB(String type);
}
public class PhoneUSB extends OrderUsb {
public PhoneUSB(CreateFactory factory) {
super(factory);
}
@Override
public void getUSB(String type) {
USBInterface usbInterface = factory.USBFactory(type);
System.out.println("的手机USB接口");
usbInterface.start();
usbInterface.stop();
}
}
public class Printers implements USBInterface {
@Override
public void start() {
System.out.println("打印机开始工作");
}
@Override
public void stop() {
System.out.println("打印机停止工作");
}
}
public class UsbFactory {
public static USBInterface create(String type) {
return switch (type) {
case "Flash" -> new Flash();
case "Printers" -> new Printers();
default -> new Flash();
};
}
}
interface USBInterface {
void start();
void stop();
}
适配器模式
桥接模式(Bridge模式)是指:将实现与抽象放在两个不同的类层次中,使两个次可层以改变。
基于类的最小设计原则,通过使用封装、聚合及继承等行为让不同的类承担不同的职责。它的主要特点是把抽象(Abstraction)与行为实现分离开来,从而可以保持各部分的独立性以及应对他们的功能扩展
概括:将抽象与实现分离,使它们可以独立变化。它是用组合关系代替继承关系来实现,从而降低了抽象和实现这两个可变维度的耦合度
核心:
抽象层与实现层分离,使两个次可层以独立改变,通过聚合进行桥接,关键是区分抽象层和实现层;桥接模式替代多层继承方案,可以减少子类的个数
抽象化(Abstraction)角色:定义抽象类,并包含一个对实现化对象的引用。
扩展抽象化(RefinedAbstraction)角色:是抽象化角色的子类,实现父类中的业务方法,并通过组合关系调用实现化角色中的业务方法。
实现化(Implementor)角色:定义实现化角色的接口,供扩展抽象化角色调用。
具体实现化(Concrete Implementor)角色:给出实现化角色接口的具体实现。
优点 :
缺点:
对于那些不希望使用继承或因为多层次继承导致系统类的个数急剧增加的系统,桥接模式尤为适用. 如:
Jdbc 的 Driver接口,如果从桥接模式来看,Driver就是一个接口,下面可以有
MySQL的Driver,Oracle的Driver,这些就可以当做实现接口类
使用桥接模式模拟消息管理
public class BridgingPattern {
public static void main(String[] args) {
QQMessage qqMessage = new QQMessage(new DelayedMessage());
qqMessage.sendMessage();
qqMessage.getMessage();
WeiXinMessage weiXinMessage = new WeiXinMessage( new timelyMessage());
weiXinMessage.sendMessage();
weiXinMessage.getMessage();
}
}
public class DelayedMessage implements Message{
@Override
public void sendMessage() {
System.out.println("发送延时消息");
}
@Override
public void getMessage() {
System.out.println("接收延时消息");
}
}
public interface Message {
void sendMessage();
void getMessage();
}
public abstract class messageTypeAbstract {
protected Message message;
public messageTypeAbstract(Message message) {
this.message = message;
}
abstract void sendMessage();
abstract void getMessage();
}
public class QQMessage extends messageTypeAbstract{
public QQMessage(Message message) {
super(message);
}
@Override
void sendMessage() {
System.out.println("QQ:");
message.sendMessage();
}
@Override
void getMessage() {
System.out.println("QQ:");
message.getMessage();
}
}
public class timelyMessage implements Message{
@Override
public void sendMessage() {
System.out.println("发送及时消息");
}
@Override
public void getMessage() {
System.out.println("接收及时消息");
}
}
public class WeiXinMessage extends messageTypeAbstract{
public WeiXinMessage(Message message) {
super(message);
}
@Override
void sendMessage() {
System.out.println("微信:");
message.sendMessage();
}
@Override
void getMessage() {
System.out.println("微信:");
message.getMessage();
}
}
动态的将新功能附加到对象上。在对象功能扩展方面,它比继承更有弹性,装饰者模式也体现了开闭原则(ocp)
动态的将新功能附加到对象和符和ocp原则
概括:动态的给对象增加一些职责,即增加其额外的功能。
核心:动态的将新功能附加到对象上;主体:被装饰者,包装:装饰者
优点:
缺点 :
public class DecoratorPattern {
public static void main(String[] args) {
CoffeeAbstract espressoCoffee = new EspressoCoffee(5.0f,"意大利咖啡");
espressoCoffee = new Milk(espressoCoffee,1.0f,"牛奶");
System.out.println(espressoCoffee.getTotalPrice());
System.out.println(espressoCoffee.getDes());
espressoCoffee = new Soy(espressoCoffee,0.5f,"豆浆");
System.out.println(espressoCoffee.getTotalPrice());
String des = espressoCoffee.getTotalDes();
System.out.println(des);
}
}
public abstract class Coffee extends CoffeeAbstract{
public float getTotalPrice(){
return super.getPrice();
}
}
public abstract class CoffeeAbstract {
String des;
float price;
public String getDes() {
return des;
}
public void setDes(String des) {
this.des = des;
}
public float getPrice() {
return price;
}
public void setPrice(float price) {
this.price = price;
}
abstract float getTotalPrice();
abstract String getTotalDes();
}
public class EspressoCoffee extends CoffeeAbstract{
public EspressoCoffee(float price,String description){
super();
setPrice(price);
setDes(description);
}
@Override
float getTotalPrice() {
return super.price;
}
@Override
String getTotalDes() {
return getDes();
}
}
public class IngredientDecorator extends CoffeeAbstract{
private final CoffeeAbstract coffee;
public IngredientDecorator(CoffeeAbstract coffee){
this.coffee = coffee;
}
@Override
float getTotalPrice() {
return price + coffee.getTotalPrice();
}
@Override
public String getTotalDes() {
return coffee.getTotalDes() + coffee.getPrice() +
des +
getPrice();
}
}
public class LongBlackCoffee extends Coffee{
float price;
public LongBlackCoffee(float price){
super();
this.price = price;
}
@Override
String getTotalDes() {
return getDes();
}
}
public class Milk extends IngredientDecorator{
public Milk(CoffeeAbstract coffee,float price,String description) {
super(coffee);
setPrice(price);
setDes(description);
}
}
public class Soy extends IngredientDecorator{
public Soy(CoffeeAbstract coffee,float price,String description) {
super(coffee);
setPrice(price);
setDes(description);
}
}
组合模式是一种结构型设计模式,又叫部分整体模式。 可以使用它将对象组合成树状结构,用来表示部分以及整体层次, 并且能像使用独立对象一样使用它们。
组合模式使得用户对单个对象和组合对象的访问具有一致性,即 :组合能让客户以一致的方式处理个别对象以及组合对象
概括:将对象组合成树状层次结构,使用户对单个对象和组合对象具有一致的访问性
优点:
缺点:
使用组合模式处理学校 学院 系别 的关系
public class College implements OrganizationComponent {
List<OrganizationComponent> organizationComponents = new ArrayList<>();//组合
String name;
String des;
public College(String name, String des){
this.name = name;
this.des = des;
}
@Override
public void add(OrganizationComponent component) {
organizationComponents.add(component);
}
@Override
public void remove(OrganizationComponent component) {
organizationComponents.remove(component);
}
public void print(){
System.out.println("--------------" +name + "--------------");
for (OrganizationComponent organizationComponent : organizationComponents) {
organizationComponent.print();
}
}
}
public class CombinationPattern {
public static void main(String[] args) {
OrganizationComponent university = new University("北京大学", "这是北京大学");
College college = new College("计算机学院", "顶级院系");
College college1 = new College("信息工程学院", "信息工程学院");
college.add(new Department("计算机科学与技术", "计算机科学与技术"));
college.add(new Department("网络工程", "网络工程"));
college.add(new Department("软件工程", "软件工程"));
college1.add(new Department("通讯工程", "通讯工程"));
college1.add(new Department("信息工程", "信息工程"));
university.add(college);
university.add(college1);
university.print();
}
}
public class Department implements OrganizationComponent{
String name;
String des;
public Department(String name, String des){
this.name = name;
this.des = des;
}
public void print(){
System.out.println(name);
}
}
public interface OrganizationComponent {
default void add(OrganizationComponent component){
}
default void remove(OrganizationComponent component){
}
void print();
}
public class University implements OrganizationComponent {
List<OrganizationComponent> organizationComponents = new ArrayList<>();
String name;
String des;
public University(String name, String des){
this.name = name;
this.des = des;
}
@Override
public void add(OrganizationComponent component) {
organizationComponents.add(component);
}
@Override
public void remove(OrganizationComponent component) {
organizationComponents.remove(component);
}
public void print(){
System.out.println("--------------" +name + "--------------");
for (OrganizationComponent organizationComponent : organizationComponents) {
organizationComponent.print();
}
}
}
外观模式是一种结构型设计模式, 能为程序库、 框架或其他复杂类提供一个简单的接口。
我们都在有意无意的大量使用外观模式。只要是高层模块需要调度多个子系统(2个以上的类对象),我们都会自觉地创建一个新的类封装这些子系统,提供精简的接口,让高层模块可以更加容易地间接调用这些子系统的功能。尤其是现阶段各种第三方SDK、开源类库,很大概率都会使用外观模式。
概括:为多个复杂的子系统提供一个一致的接口,使这些子系统更加容易被访问
核心:使用高层次的抽象类或者接口来组合使用复杂的子系统,是使用者调用子系统简介化,无需关心子系统的内部细节。
优点:
缺点:
MyBatis 中的Configuration 去创建MetaObject 对象使用到外观模式
public class Bargain {
public void bargain(){
System.out.println("病人开始划价");
}
}
public class Client {
public static void main(String[] args) {
ReceptionistFacade receptionistFacade = new ReceptionistFacade();
receptionistFacade.receptionist(new User("Tom"));
}
}
public class OutpatientDepartment {
public void outpatientDepartment(){
System.out.println("病人开始门诊");
}
}
public class ReceptionistFacade {
private final Bargain bargain = new Bargain();
private final OutpatientDepartment outpatientDepartment = new OutpatientDepartment();
private final Register register = new Register();
private final TakeMedicine takeMedicine = new TakeMedicine();
public void receptionist(User user){
System.out.println("接待员开始接待"+user.name);
register.register();
outpatientDepartment.outpatientDepartment();
bargain.bargain();
takeMedicine.takeMedicine();
}
}
public class Register {
public void register(){
System.out.println("病人开始挂号");
}
}
public class TakeMedicine {
public void takeMedicine(){
System.out.println("病人开始取药");
}
}
public class User {
public String name;
public User(String name){
this.name = name;
}
}
用共享技术来有效地支持大量细粒度对象的复用。它通过共享已经存在的对象来大幅度减少需要创建的对象数量、避免大量相似类的开销,从而提高系统资源的利用率。
常用于系统底层开发,解决系统的性能问题。像数据库连接池,里面都是创建好的连接对象,这些连接对象中有我们需要的则直接拿来用,避免重新创建,如果没有我们需要的,则创建一个
享元模式能够解决 重复对象的内存浪费的问题,当系统中有大量相似对象,需要缓冲池时。不需总是创建新对象,可以从缓冲池里拿。这样可以降低系统内存,同时提高效率
概括:运用共享技术来有效地支持大量细粒度对象的复用,有就共享,没有就创建
享元模式提出了两个要求:细粒度和共享对象。这里就涉及到内部状态和外部状态了,即将对象的信息分为两个部分:内部状态和外部状态
内部状态(共享状态)指对象共享出来的信息,存储在享元对象内部且不会随环境的改变而改变
外部状态(非共享状态)指对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。
优点:
缺点:
为了使对象可以共享,需要将一些不能共享的状态外部化,这将增加程序的复杂性
共享状态和非共享状态需要正确区分出来
读取享元模式的外部状态会使得运行时间稍微变长
public class LibraryFlyweightFactory {
HashMap<String,BookFlyweight> hashMap = new HashMap<>();
public BookFlyweight getBook(String bookName){
if (!hashMap.containsKey(bookName)){
// hashMap.put(bookName, new BookFlyweight(bookName) {
// @Override
// void borrow(User user) {
// System.out.println(user.name + "借书"+bookName);
// }
// });
hashMap.put(bookName, new ConcreteBookA(bookName));
}
return hashMap.get(bookName);
}
public int size() {
return hashMap.size();
}
}
public class FlyweightPattern {
public static void main(String[] args) {
LibraryFlyweightFactory factory = new LibraryFlyweightFactory();
BookFlyweight bookA = factory.getBook("设计模式");
BookFlyweight bookB = factory.getBook("数据结构");
BookFlyweight bookC = factory.getBook("JVM");
bookA.borrow(new User("tom"));
bookA.borrow(new User("jack"));
bookB.borrow(new User("leo"));
bookC.borrow(new User("ben"));
System.out.println(factory.size());
}
}
public class ConCreteBookB extends BookFlyweight{
public ConCreteBookB(String bookName) {
super(bookName);
}
@Override
public void borrow(User user) {
System.out.println(user.name + "借书B");
}
}
public class ConcreteBookA extends BookFlyweight{
public ConcreteBookA(String bookName) {
super(bookName);
}
@Override
public void borrow(User user) {
System.out.println(user.name + "借书 "+bookName);
}
}
public abstract class BookFlyweight {
String bookName;
public BookFlyweight(String bookName) {
this.bookName = bookName;
}
abstract void borrow(User user);
}
代理模式
模板方法模式是一种行为设计模式, 它在超类中定义了一个算法的框架, 允许子类在不修改结构的情况下重写算法的特定步骤。
模板方法模式在一个抽象类公开定义了执行它的方法的模板。它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行
概括:定义一个操作中的算法骨架,而将算法的一些步骤延迟到子类中,使得子类可以不改变该算法结构的情况下重定义该算法的某些特定步骤。
一般模板方法都加上final关键字, 防止子类重写模板方法
模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法。
基本方法:是整个算法中的一个步骤,包含以下几种类型。
抽象方法:在抽象类中声明,由具体子类实现。
具体方法:在抽象类中已经实现,在具体子类中可以继承或重写它。
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种
Spring IOC容器初始化时运用到的模板方法模式
优点:
缺点:
只希望客户端扩展某个特定算法步骤, 而不是整个算法或其结构时, 可使用模板方法模式。
当需要控制子类的扩展时,模板方法只在特定点调用钩子操作,这样就只允许在这些点进行扩展。
当要完成在某个过程,该过程要执行一系列步骤,这一系列的步骤基本相同,但其个别步骤在实现时可能不同,通常考虑用模板方法模式来处理。
public class TemplatePattern {
public static void main(String[] args) {
AbstractTemplate milk = new MungBeanMilk();
milk.make();
System.out.println("*******************");
AbstractTemplate redSoybeanMilk = new RedSoybeanMilk();
redSoybeanMilk.make();
System.out.println("*******************");
AbstractTemplate sugarFreeBeanMilk = new SugarFreeBeanMilk();
sugarFreeBeanMilk.make();
}
}
public abstract class AbstractTemplate {
public final void make(){
selected();
if (isAdd())
add();
soak();
stir();
}
protected void selected(){
System.out.println("选材料");
}
abstract void add();
protected void soak(){
System.out.println("浸泡");
}
protected void stir(){
System.out.println("搅拌");
}
protected boolean isAdd(){
return true;
}
}
public class MungBeanMilk extends AbstractTemplate {
@Override
void add() {
System.out.println("加入绿豆");
}
}
public class RedSoybeanMilk extends AbstractTemplate{
@Override
void add() {
System.out.println("加入红豆");
}
}
public class SugarFreeBeanMilk extends AbstractTemplate{
@Override
void add() {
System.out.println("加糖");
}
public boolean isAdd(){
return false;
}
}
是指给定一个语言(表达式),定义它的文法的一种表示,并定义一个解释器,使用该解释器来解释语言中的句子(表达式)
概括:提供如何定义语言的文法,以及对语言句子的解释方法,即解释器。
优点:
扩展性好。由于在解释器模式中使用类来表示语言的文法规则,因此可以通过继承等机制来改变或扩展文法。
缺点:
Spring框架中 SpelExpressionParser就使用到解释器模式
public abstract class AbstractExpression {
abstract boolean interpret(String string);
}
public class Context {
private final AbstractExpression cityPerson;
public Context(String[] citys,String[] persons) {
AbstractExpression city = new TerminalExpression(citys);
AbstractExpression person = new TerminalExpression(persons);
cityPerson = new NoTerminalExpression(city, person);
}
public void freeRide(String info) {
boolean ok = cityPerson.interpret(info);
if (ok) System.out.println("您是" + info + ",您本次乘车免费!");
else System.out.println(info + ",您不是免费人员,本次乘车扣费2元!");
}
}
public class InterpreterPattern {
public static void main(String[] args) {
Context bus = new Context(new String[]{"韶关", "广州"},new String[] {"老人", "妇女", "儿童"});
bus.freeRide("韶关的老人");
bus.freeRide("韶关的年轻人");
bus.freeRide("广州的妇女");
bus.freeRide("广州的儿童");
bus.freeRide("山东的儿童");
}
}
public class NoTerminalExpression extends AbstractExpression{
private final AbstractExpression city;
private final AbstractExpression person;
public NoTerminalExpression(AbstractExpression city, AbstractExpression person) {
this.city = city;
this.person = person;
}
@Override
public boolean interpret(String info) {
String[] s = info.split("的");
return city.interpret(s[0]) && person.interpret(s[1]);
}
}
public class TerminalExpression extends AbstractExpression{
private final Set<String> set = new HashSet<>();
public TerminalExpression(String[] data) {
Collections.addAll(set, data);
}
public boolean interpret(String info) {
return set.contains(info);
}
}
命令模式
访问者模式
迭代器模式
观察者模式
中介者模式
备忘录模式
状态模式
策略模式
职责链模式