无论是设计原则还是设计模式,都是一种思想,程序就是依据这些思想来进行开发的。学习设计模式之前,首先要知道设计原则,因为设计模式与设计原则息息相关,如果跳过设计原则直接学习设计模式就会很懵,学不明白。
了解设计原则后再来学习设计模式会事半功倍,不仅能知其然还能知其所以然。
七大设计原则
1. 单一职责原则
- Single Responsibility Principle, SRP
- 核心思想:解耦和增强内聚(高内聚,低耦合)
- 一个类或者一个模块只完成一个职责
一个程序就像一台车,需要多个零部件互相配合才能跑起来就像一个复杂的程序也需要多个类互相调用才能跑起来。
每一个零部件都有各自单一的功能,当某个功能出现问题时,只需要找到对应的零件进行维修,而不需要动其他没有故障的零件。就像是程序出现问题时,只需要修改出现问题的类进行修改,不必修改其他的完好的类。当然这一切都要建立在单一职责原则上。
2.里氏替换原则
- Liskov Substitution Principle, LSP
- 核心思想:任何父类出现的地方,子类都可以替代出现
里氏替换是针对继承而言的。子类可以替代父类所有出现的地方,这样才能真正实现代码的可复用性,同时这也反应了体现了接口与接口实现类之间的关系。
3.依赖倒置原则
- Dependence Inversion Principle, DIP
- 核心思想:要依赖于抽象,不要依赖于具体的实现
意思是要对抽象进行编程,不要对实现进行编程。就比如汽车是接口,宝马X6,奥迪Q7,红旗H9是接口实现类,司机要开车,无论他开的宝马X6,奥迪Q7还是红旗H9都不重要,反正他开的肯定是车。
假如有一天司机要开劳斯莱斯幻影,这些都跟宝马X6,奥迪Q7,红旗H9没有任何关系,他只需要在汽车的接口的基础上重新定义一个劳斯莱斯幻影的接口实现类就可以了,这就叫面向接口编程,目的是降低程序的耦合度。
4.迪米特原则/最少知识原则
- Law of Demeter, LoD
- 又称最少知识原则
- 核心思想:一个对象应当尽可能少的了解其他的对象,不和陌生人说话,降低各个对象之间的耦合,提高系统的可维护性
一个类应当对自己需要耦合或者调用的类,知道得最少,被调用的类内部有多复杂都不需要在乎,只需要知道被调用类中自己所需要的就行了
5.开闭原则
- Open-Closed Principle, OCP
- 核心思想:对扩展开放,对修改关闭
当业务增加了新的需求,需要添加新功能,那么开闭原则就是在不改变原有代码的基础上,进行拓展。之所以要规定不改变原有代码,是因为为了防止把之前没有问题的代码改出问题来,或者是更改的别人的代码,从而引发的一系列问题。
6.接口分离原则
- Interface Segregation Principle, ISP
- 核心思想:不应该强迫程序依赖他们不需要使用的方法
一个接口不需要提供太多的功能(不违反单一职责原则),接口应当尽可能的小,且尽可能的细化。一个接口提供过多功能,就会很臃肿,不利于功能的扩展,“屎山”的建立非一朝一夕。
7.合成复用原则
- Composite Reuse Principle, CRP
- 核心思想:尽可能使用对象组合,而不是继承来达到复用的目的
继承关系是强耦合,组合关系是低耦合。尽可能在满足里氏替换原则的时候才使用继承,其他时候应当使用组合来代替继承。使用组合就是将*功能一致的子功能(属性和方法)合成为一个单独的模块(类),然后在主类中调用这个模块即可*。
设计模式
工厂方法模式
定义:定义一个创建对象的接口,让子类决定实例化哪一个类。工厂方法使一个类的实例化推迟到其子类
工厂方法模式有4要素,抽象工厂(汽车工厂),具体工厂(BWM汽车工厂),抽象产品(汽车),具体产品(BWM汽车)
首先定义一个汽车接口
public interface Car{
void wheel();
void engine();
void window();
void chair();
}
BMW类,Benz类实现汽车接口
BWM类
public class BMW implements Car {
public void wheel() {
System.out.println("宝马的轮子");
}
public void engine() {
System.out.println("宝马的发动机");
}
public void window() {
System.out.println("宝马的车窗");
}
public void chair() {
System.out.println("宝马的座椅");
}
}
BenZ类
public class BenZ implements Car {
public void wheel() {
System.out.println("奔驰的轮子");
}
public void engine() {
System.out.println("奔驰的发动机");
}
public void window() {
System.out.println("奔驰的车窗");
}
public void chair() {
System.out.println("奔驰的座椅");
}
}
汽车工厂生产汽车
public abstract class CarFactory {
protected abstract Car makeCar(String carType);
public Car produceCar(String carType) {
Car car = makeCar(carType);
car.wheel();
car.engine();
car.window();
car.chair();
return car;
}
}
中国的汽车工厂生产BMW汽车和Benz汽车
public class ChinaFactory extends CarFactory {
protected Car makeCar(String carType) {
Car car = null;
if (carType.equals("BWM")) {
car = new ChinaBMWCar();
} else if (carType.equals("Benz")) {
car = new ChinaBenzCar();
}
return car;
}
}
工厂方法把实例化推迟到子类
private static void carFactoryTest() {
carFactory carfactory = new ChinaFactory();
carfactory.produceCar("BMW");
}
抽象工厂模式
定义:通过接口来创建一组产品
当业务更复杂的时候会使用抽象工厂模式来代替工厂模式。抽象工厂模式是建立在里氏替换原则和依赖倒置原则的基础上。就拿汽车举例,生产汽车需要用到材料有,钢铁,玻璃,橡胶
汽车材料接口:钢铁,玻璃,橡胶
public interface Steel {
void description();
}
public interface Glass {
void description();
}
public interface Rubber {
void description();
}
汽车材料接口实现类
public class GoodSteel implements Steel{
public void description(){
system.out.println("好的钢铁");
}
}
public class GoodGlass implements Glass{
public void description(){
system.out.println("好的玻璃");
}
}
public class GoodRubber implements Rubber{
public void description(){
system.out.println("好的橡胶");
}
}
汽车材料工厂接口
public interface CarmakingsFactory {
Steel creatSteel();
Glass creatGlass();
Rubber creatRubber();
}
中国汽车材料工厂实现汽车材料工厂接口
public class ChinaCarmakingsFactory implements CarmakingsFactory{
public Steel creatSteel(){
return new GoodSteel;
}
public Glass creatGlass(){
return new GoodGlass;
}
public Rubber creatRubber(){
return new GoodRubber;
}
}
汽车类
public abstract class Car {
protected Steel steel;
protected Glass glass;
protected Rubber rubber;
protected CarmakingsFactory carmakingsFactory;
/** 准备汽车材料 */
public abstract void prepare();
public void wheel() {
System.out.println("汽车轮胎");
}
public void windows() {
System.out.println("汽车车窗");
}
public void chair() {
System.out.println("汽车座椅");
}
}
BMW汽车类
public class BMW extends Car {
public BMW(CarmaingsFactory carmakingsFactory) {
this.pizzaIngredientFactory = pizzaIngredientFactory;
}
public void prepare() {
System.out.println("BMW汽车材料准备");
steel = carmakingsFactory.createSteel();
glass = carmakingsFactory.createGlass();
rubber = carmakingsFactory.createRubber();
}
}
单例模式
定义:确保一个类只有一个实例,并提供一个全局访问点
五种实现方式
- 饿汉式
- 懒汉式
- 双重校验
- 静态内部类
- 枚举类
//饿汉式(线程安全,调用效率高,但是不能延时加载)
public class SingletonDemo1 {
//无论用不用都先创建了实例
private static SingletonDemo1 instance = new SingletonDemo1();
private SingletonDemo1(){}
public static SingletonDemo1 getInstance(){
return instance;
}
}
//懒汉式(线程安全,调用效率不高,但是能延时加载)
public class SingletonDemo2 {
//类初始化时,不初始化这个对象(延时加载,真正用的时候再创建)
private static SingletonDemo2 instance;
//构造器私有化
private SingletonDemo2(){}
//方法同步,调用效率低
public static synchronized SingletonDemo2 getInstance(){
if(instance==null){
instance=new SingletonDemo2();
}
return instance;
}
}
//双重校验
public class SingletonDemo3 {
private volatile static SingletonDemo3 singletonDemo3;
private SingletonDemo3() {}
public static SingletonDemo3 newInstance() {
if (singletonDemo3 == null) {
synchronized (SingletonDemo3.class) {
if (singletonDemo3 == null) {
singletonDemo3 = new SingletonDemo3();
}
}
}
return singletonDemo3;
}
}
//静态内部类(线程安全,调用效率高,可以延时加载)
public class SingletonDemo4 {
//静态内部类
private static class SingletonClassInstance{
private static final SingletonDemo4 instance = new SingletonDemo4();
}
private SingletonDemo4(){}
public static SingletonDemo4 getInstance(){
return SingletonClassInstance.instance;
}
}
//枚举类
public enum SingletonDemo5 {
//枚举元素本身就是单例
INSTANCE;
//添加自己需要的操作,直接通过SingletonDemo5.INSTANCE.doSomething()的方式调用即可。方便、简洁又安全。
public void doSomething() {
System.out.println("doSomething");
}
}
class Test {
public static void main(String[] args) {
SingletonDemo5.INSTANCE.doSomething();
}
}
适配器模式
定义:将一个类的接口,转换成客户期望的另一个接口。适配器让原本接口不兼容的类可以合作无间。
Target接口
public interface Target {
void prepare();
void execute();
}
适配器类
public class Adapter implements Target {
// 待适配的类
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
this.adaptee = adaptee;
}
public void prepare() {
adaptee.prepare1();
adaptee.prepare2();
adaptee.prepare3();
}
public void execute() {
adaptee.doingSomething();
}
}
带适配的类
public class Adaptee {
public void prepare1() {
System.out.println("Adaptee prepare1()");
}
public void prepare2() {
System.out.println("Adaptee prepare2()");
}
public void prepare3() {
System.out.println("Adaptee prepare3()");
}
public void doingSomething() {
System.out.println("Adaptee doingSomething()");
}
}
正常的符合Target接入标准的类
public class NormalTarget implements Target {
public void prepare() {
System.out.println("NormalTarget prepare()");
}
public void execute() {
System.out.println("NormalTarget execute()");
}
}
客户端只需要关注调用的target是哪一个
public class Client {
Target target;
public void work() {
target.prepare();
target.execute();
}
public void setTarget(Target target) {
this.target = target;
}
}
装饰者模式
定义:动态地将责任附加到对象上。若要扩展功能,装饰者提供了比继承更有弹性的替代方案。
饮品抽象类
public abstract class Beverage {
String description = "Unknown";
public String getDescription() {
return description;
}
public abstract double cost();
}
调料抽象类
public abstract class CondimentDecorator extends Beverage {
public abstract String getDescription();
}
饮品具体实现类
public class DarkRoast extends Beverage {
public DarkRoast() {
description = "Dark Roast Coffee";
}
public double cost() {
System.out.println("DarkRoast case:" + 1.99);
return 1.99;
}
}
调料具体实现类
public class Mocha extends CondimentDecorator {
private Beverage beverage;
public Mocha(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return "Mocha";
}
public double cost() {
System.out.println("Mocha case:" + 0.99);
return 0.99 + beverage.cost();
}
}
调料具体实现类
public class Whip extends CondimentDecorator {
private Beverage beverage;
public Whip(Beverage beverage) {
this.beverage = beverage;
}
public String getDescription() {
return "Whip";
}
public double cost() {
System.out.println("Whip case:" + 0.5);
return 0.5 + beverage.cost();
}
}
原型模式
定义:将一个对象作为原型,通过对其进行复制而克隆出多个和原型类似的新实例
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。也就是说,这种不通过new关键字来产生一个对象,而是通过对象复制(Java中的clone或者反序列化)来实现的模式,就叫做原型模式。
优点:
- 原型模式是在内存二进制流的复制,要比直接new一个对象性能高,尤其是在一个循环内产生大量的对象。
- 直接在内存中复制,避免调用构造函数。
使用场景:
- 类的初始化需要消耗非常多的资源
- 通过new产生一个对象非常繁琐的数据准备或访问
- 一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值。
public class Prototype implements Cloneable {
public static void main(String[] args) {
Prototype prototype = new Prototype();
//通过clone方法创建的Prototype对象不会执行构造方法
Prototype clonePrototype = prototype.clone();
}
public Prototype() {
System.out.println("-----Prototype的构造方法被执行了!-----");
}
@Override
protected Prototype clone() {
try {
return (Prototype)super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return null;
}
}
建造者模式
定义:使用建造者模式,可以封装一个产品的构造过程,并允许按步骤构造产品
优点:
- 将一个复杂的创建过程封装起来
- 允许对象通过多个步骤来创建,并且可以改变过程
- 向客户隐藏内部的表现
- 产品的实现可以被替换,因为客户只看到一个抽象接口
- 经常被用来创建组合结构
建造行为接口
public interface Builder {
// 安装引擎
Builder initalEngine(String engine);
// 安装齿轮
Builder initalGear(String gear);
// 安装车门
Builder initalDoor(String door);
// 安装轮胎
Builder initailWheel(String wheel);
// 获得构建后的汽车
Car getCar();
}
汽车类
@ToString
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Car {
private String engine = "普通标准的发动机";
private String gear = "普通标准的齿轮";
private String door = "普通标准的车门";
private String wheel = "普通标准的轮胎";
}
构建车
public class Worker {
Car createA4LCar() {
return new AudiBuilder().initalEngine("Audi的4缸发动机").initalGear("6速双离合变速箱").getCar();
}
Car createR8Car() {
return new AudiBuilder().initalEngine("16缸跑车引擎").initalDoor("碳纤维轻量级车门").initalGear("7档湿式双离合变速箱").initailWheel("米其林Top2竞速级轮胎").getCar();
}
Car createCommonBMW() {
return new BMWBuilder().getCar();
}
}
奥迪车构建类
public class AudiBuilder implements Builder {
private Car car;
public AudiBuilder() {
car = new Car("Audi普通的发动机",
"Audi普通标准的齿轮",
"Audi普通标准的车门",
"Audi普通标准的轮胎");
}
@Override
public Builder initalEngine(String engine) {
car.setEngine(engine);
return this;
}
@Override
public Builder initalGear(String gear) {
car.setGear(gear);
return this;
}
@Override
public Builder initalDoor(String door) {
car.setDoor(door);
return this;
}
@Override
public Builder initailWheel(String wheel) {
car.setWheel(wheel);
return this;
}
@Override
public Car getCar() {
return car;
}
}
宝马车构建类
public class BMWBuilder implements Builder {
private static Car car = new Car("BMW普通的发动机",
"BMW普通标准的齿轮",
"BMW普通标准的车门",
"BMW普通标准的轮胎");
@Override
public Builder initalEngine(String engine) {
car.setEngine(engine);
return this;
}
@Override
public Builder initalGear(String gear) {
car.setGear(gear);
return this;
}
@Override
public Builder initalDoor(String door) {
car.setDoor(door);
return this;
}
@Override
public Builder initailWheel(String wheel) {
car.setWheel(wheel);
return this;
}
@Override
public Car getCar() {
return car;
}
}
建造者模式测试类
public class BuilderTest {
public static void main(String[] args) {
Worker worker = new Worker();
Car audiR8 = worker.createR8Car();
Car audiA4L = worker.createA4LCar();
Car commonBMW = worker.createCommonBMW();
System.out.println("audiR8=" + audiR8);
System.out.println("audiA4L=" + audiA4L);
System.out.println("commonBMW=" + commonBMW);
}
}
代理模式
定义:代理模式为某对象提供一种代理以控制对该对象的访问。即:客户端通过代理间接地访问该对象,从而限制、增强或修改该对象的一些属性
代理模式可以在不修改原有类的情况下,对一个业务类进行横向扩展,比如,增加请求与响应的日志,增加权限校验,增加远程请求对象封装。
subject接口
public interface Subject {
void request();
}
subject接口实现类
public class RealSubject implements Subject {
@Override
public void request() {
System.out.println("-----RealSubject 开始执行业务操作-----");
}
}
创建代理类
public class Proxy implements Subject {
// 被代理的对象
private Subject subject;
public Proxy(Subject subject) {
this.subject = subject;
}
@Override
public void request() {
beforeProcessor();
//在调用前和调用后都可以执行操作
subject.request();
afterProcessor();
}
private void beforeProcessor() {
System.out.println("-----Proxy before processor-----");
}
private void afterProcessor() {
System.out.println("-----Proxy after processor-----");
}
}
测试代理模式
public class ProxyTest {
public static void main(String[] args) {
Subject subject = new Proxy(new RealSubject());
subject.request();
//如果没有代理模式是下面这样
//Subject subject = new RealSubject();
//subject.request();
}
}
桥接模式
定义:将抽象部分和实现部分,分离解耦,使得两者可以独立地变化。桥接模式通过将实现和抽象放在两个不同的类层次中而使得它们可以独立变化
优点:
- 将实现解耦,抽象和实现可以独立扩展,不会影响到对方
- 对于“具体的抽象类”所做的改变,不会影响到客户
- 当需要用不同的方式改变接口和实现时,桥接模式很好用
颜色大类接口
public interface ColorImplementor {
String getColor();
}
抽象画笔类
@Data
public abstract class BrushPenAbstraction {
// 颜色接口
protected ColorImplementor color;
// 绘画操作
public abstract void draw();
}
细毛笔实现类继承画笔抽象类
public class SmallBurshPen extends BrushPenAbstraction {
@Override
public void draw() {
System.out.println("Small and " + color.getColor() + " drawing!");
}
}
粗毛笔实现类继承画笔抽象类
public class BigBurshPen extends BrushPenAbstraction {
@Override
public void draw() {
System.out.println("Big and " + color.getColor() + " drawing!");
}
}
蓝色墨水类实现墨水大类
public class BlueColor implements ColorImplementor {
@Override
public String getColor() {
return "Blue";
}
}
红色墨水类实现墨水大类
public class RedColor implements ColorImplementor {
@Override
public String getColor() {
return "Red";
}
}
桥接模式测试类
public class BridgeTest {
public static void main(String[] args) {
BrushPenAbstraction brushPen = new BigBurshPen();
brushPen.setColor(new RedColor());
brushPen.draw();
brushPen.setColor(new BlueColor());
brushPen.draw();
brushPen = new SmallBurshPen();
brushPen.setColor(new BlueColor());
brushPen.draw();
}
}
外观模式
定义:提供了一个统一的接口,用来访问子系统中的多个接口。外观定义了一个上层的接口,让子系统更容易使用
汽车类
public class Car {
private Engine engine;
private Door door;
private DashboardDisplay display;
private Key key;
public Car() {
engine = new Engine();
door = new Door();
display = new DashboardDisplay();
key = new Key();
}
/** 汽车启动 */
public void start() {
//钥匙启动
if (key.turns()) {
door.lock();
engine.start();
display.refreshDisplay();
}
}
}
具体实现:钥匙,门,发动机,中控显示屏
public class Key {
public boolean turns() {
System.out.println("Key turns");
return true;
}
}
public class Door {
public void lock() {
System.out.println("Door lock");
}
}
public class Engine {
public void start() {
System.out.println("Engine start");
}
}
public class DashboardDisplay {
void refreshDisplay() {
System.out.println("DashboardDisplay refreshDisplay");
}
}
外观模式测试类
public class ClientTest {
public static void main(String[] args) {
Car car = new Car();
car.start(); // 启动汽车,用户并不知道引擎、车门、钥匙、中控的运作
}
}
享元模式
定义:使用共享对象可以有效地支持大量的细粒度的对象。享元模式是池技术的重要实现方式
有很多人去做核酸,人做核酸的信息有姓名,地址,核酸机构;核酸机构的信息有ID,机构名称
@Data
@NoArgsConstructor
@AllArgsConstructor
//人员信息实体类
public class PersonInfo {
// 姓名
private String name;
// 居住的详细地址
private String address;
// 核酸医院或网点唯一标识
private Integer nucleicId;
}
@Data
@AllArgsConstructor
@NoArgsConstructor
//核酸机构和网点信息
public class NucleicInfo {
// 唯一标识
private Integer id;
// 核酸机构网点名称
private String name;
}
核酸机构和网店信息客户端
public class NucleicInfoClient {
// 存储核酸机构和网点的池pool
private HashMap<Integer, NucleicInfo> pool = Maps.newHashMap();
// 构造函数中初始化池中数据
public NucleicInfoClient() {
NucleicInfo nucleicInfo;
for (int i = 1; i <=10; i++) {
nucleicInfo = new NucleicInfo(i, "北京市第"+i+"医院核酸网点");
pool.put(nucleicInfo.getId(), nucleicInfo);
}
}
public NucleicInfo getNucleicInfo(Integer key) {
if (key == null || !pool.containsKey(key)) {
return null;
}
return pool.get(key);
}
}
享元模式测试类
public class FlyweightTest {
private static NucleicInfoClient client = new NucleicInfoClient();
public static void main(String[] args) {
PersonInfo bob = new PersonInfo("bob", "北京市海淀区xx大街xx小区x号楼x号", 2);
PersonInfo muse = new PersonInfo("muse", "北京市朝阳区yy大街yy小区y号楼y号", 7);
PersonInfo john = new PersonInfo("john", "上海市市徐汇区zz大街zz小区z号楼z号", 4);
printPersonInfo(bob);
printPersonInfo(muse);
printPersonInfo(john);
}
public static void printPersonInfo(PersonInfo personInfo) {
NucleicInfo nucleicInfo = client.getNucleicInfo(personInfo.getNucleicId());
System.out.println(String.format("姓名=%s 居住地址=%s 核酸网点=%s", personInfo.getName(), personInfo.getAddress(),
nucleicInfo.getName()));
}
}
组合模式
定义:允许将对象组合成树形结构来表现“整体/部分”层次结构。组合能让客户以一致的方式处理个别对象以及对象组合。
职员类
//添加有参数的构造方法
@AllArgsConstructor
public abstract class AbstractCorp {
// 职员姓名
private String name = "";
// 职员的职位
private String position = "";
// 职员的薪水
private int salary = 0;
// 获得职员信息
public String getCorpInfo() {
return String.format("姓名:%s 职位:%s 薪水:%d", name, position, salary);
}
}
基层员工(叶子结点)
public class LeafCorp extends AbstractCorp {
public LeafCorp(String name, String position, int salary) {
super(name, position, salary);
}
}
管理层员工(非叶子结点)
public class BranchCorp extends AbstractCorp {
private ArrayList<AbstractCorp> corps = Lists.newArrayList();
public BranchCorp(String name, String position, int salary) {
super(name, position, salary);
}
// 添加职员
public void addSubCorp(AbstractCorp... corp) {
corps.addAll(Arrays.asList(corp));
}
// 返回手下的职员
public ArrayList<AbstractCorp> getSubCorp() {
return corps;
}
}
组合模式测试类
public class CompositeTest {
public static void main(String[] args) {
// 创建公司所有职员
BranchCorp a = new BranchCorp("A", "董事长", 100000);
BranchCorp b = new BranchCorp("B", "技术总监", 70000);
BranchCorp c = new BranchCorp("C", "人事总监", 60000);
BranchCorp d = new BranchCorp("D", "财务总监", 50000);
LeafCorp b1 = new LeafCorp("B1", "程序员", 30000);
LeafCorp b2 = new LeafCorp("B2", "程序员", 20000);
LeafCorp c1 = new LeafCorp("C1", "HR", 15000);
LeafCorp d1 = new LeafCorp("D1", "会计", 13000);
// 根据下属关系,构建树形结构
a.addSubCorp(b, c, d);
b.addSubCorp(b1, b2);
c.addSubCorp(c1);
d.addSubCorp(d1);
// 获得下属信息
System.out.println("-----a的下属-----");
getSubCorp(a);
System.out.println("-----b的下属-----");
getSubCorp(b);
}
// 获得branchCorp的下属
private static void getSubCorp(BranchCorp branchCorp) {
for (AbstractCorp corp : branchCorp.getSubCorp()) {
System.out.println("corp = " + corp.getCorpInfo());
if (corp instanceof BranchCorp) {
getSubCorp((BranchCorp) corp);
}
}
}
}
模版方法模式
定义:在一个方法中定义一个算法骨架,而将一些步骤延迟到子类中。模版方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步骤
饮品制作类(抽象类定义一个通用的”算法骨架“)
public abstract class MakeBeverage {
// 准备食谱(防止子类覆盖这个方法)
final void prepareRecipe() {
/** 第一步:把水煮沸 */
boilWater();
/** 第二步:酿造饮品 */
brew();
/** 第三步:把饮品倒入杯子中 */
pourInCup();
/** 第四步:往饮品中增加调味品 */
addCondiments();
}
// 酿造
abstract void brew();
// 往饮品中增加调味品
abstract void addCondiments();
protected void boilWater() {
System.out.println("把水煮沸");
}
private void pourInCup() {
System.out.println("把饮品倒入杯子中");
}
}
咖啡类
public class Coffee extends MakeBeverage {
@Override
protected void brew() {
System.out.println("用沸水冲泡咖啡");
}
@Override
protected void addCondiments() {
System.out.println("往咖啡中添加糖和牛奶");
}
}
茶类
public class Tea extends MakeBeverage {
@Override
protected void brew() {
System.out.println("用沸水浸泡茶叶");
}
@Override
protected void addCondiments() {
System.out.println("往茶叶中添加柠檬");
}
}
模板方法模式测试类
public class TemplateTest {
public static void main(String[] args) {
System.out.println("-----------开始冲泡茶叶-----------");
Tea tea = new Tea();
tea.prepareRecipe();
System.out.println("-----------开始冲泡咖啡-----------");
Coffee coffee = new Coffee();
coffee.prepareRecipe();
}
}
命令模式
定义:将“请求”封装成命令对象,以便使用不同的请求、队列、或者日志来参数化其他对象
操作接口
public interface Command {
void execute();
}
灯类
public class Light {
/** 开灯操作 */
public void on() {
System.out.println("Light on!");
}
/** 关灯操作 */
public void off() {
System.out.println("Light off!");
}
}
关灯操作
public class LightOffCommand implements Command {
private Light light;
public LightOffCommand(Light light) {
this.light = light;
}
public void execute() {
light.off();
}
}
开灯操作
public class LightOnCommand implements Command {
private Light light;
public LightOnCommand(Light light) {
this.light = light;
}
public void execute() {
light.on();
}
}
遥控器类
public class RemoteController {
private Command[] onCommands;
private Command[] offCommands;
public RemoteController() {
onCommands = new Command[8];
offCommands = new Command[8];
for (int i = 0; i < 8; i++) {
onCommands[i] = new NoCommand();
offCommands[i] = new NoCommand();
}
}
/** 往遥控器中添加命令 */
public void addCommand(int slot, Command onCommand, Command offCommand) {
onCommands[slot] = onCommand;
offCommands[slot] = offCommand;
}
/** 按遥控器中某个开启键 */
public void pushOnButton(int slot) {
onCommands[slot].execute();
}
/** 按遥控器中某个关闭键 */
public void pushOffButton(int slot) {
offCommands[slot].execute();
}
}
命令模式测试类
public class CommandTest {
public static void main(String[] args) {
Light light = new Light();
RemoteController controller = new RemoteController();
//遥控器赋值
controller.addCommand(0, new LightOnCommand(light), new LightOffCommand(light));
// 按下遥控器,第一排的ON按钮
controller.pushOnButton(0);
// 按下遥控器,第一排的OFF按钮
controller.pushOffButton(0);
}
}
责任链莫斯
定义:当你想要让一个以上的对象有机会能够处理某个请求的时候,就使用责任链模式。使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系
将这些对象连成一条链,并沿着这条链传递该请求,直到有对象处理它为止。
抽象处理类
public abstract class AbstractProcessor {
// 责任链中下一个处理节点
private AbstractProcessor nextProcessor;
// 返回的处理结果
private String result;
public final String handleMessage(List<Email> emails) {
List<Email> filterEmails =
emails.stream().filter(email -> email.getType() == this.emailType()).collect(Collectors.toList());
result = this.execute(filterEmails);
if (this.nextProcessor == null) {
return result;
}
return this.nextProcessor.handleMessage(emails);
}
// 设置责任链的下一个处理器
public void setNextProcessor(AbstractProcessor processor) {
this.nextProcessor = processor;
}
// 获得当前Processor可以处理的邮件类型
protected abstract int emailType();
// 具体处理方法
protected abstract String execute(List<Email> emails);
}
业务部门处理类
public class BusinessProcessor extends AbstractProcessor {
@Override
protected int emailType() {
return EmailType.COOPERATE_EMAIL.type;
}
@Override
protected String execute(List<Email> emails) {
if (CollectionUtils.isNotEmpty(emails)) {
System.out.println("-------业务部门开始处理邮件-------");
emails.stream().forEach(email -> System.out.println(email.getContent()));
}
return "任务执行完毕!";
}
}
CEO处理类
public class CeoProcessor extends AbstractProcessor {
@Override
protected int emailType() {
return EmailType.FANS_EMAIL.type;
}
@Override
protected String execute(List<Email> emails) {
if (CollectionUtils.isNotEmpty(emails)) {
System.out.println("-------CEO开始处理邮件-------");
emails.stream().forEach(email -> System.out.println(email.getContent()));
}
return "任务执行完毕!";
}
}
垃圾邮件处理类
public class GarbageProcessor extends AbstractProcessor {
@Override
protected int emailType() {
return EmailType.GARBAGE_EMAIL.type;
}
@Override
protected String execute(List<Email> emails) {
if (CollectionUtils.isNotEmpty(emails)) {
System.out.println("-------垃圾开始处理邮件-------");
emails.stream().forEach(email -> System.out.println(email.getContent()));
}
return "任务执行完毕!";
}
}
法律部门处理类
public class LawProcessor extends AbstractProcessor {
@Override
protected int emailType() {
return EmailType.SLANDER_EMAIL.type;
}
@Override
protected String execute(List<Email> emails) {
if (CollectionUtils.isNotEmpty(emails)) {
System.out.println("-------法律部门开始处理邮件-------");
emails.stream().forEach(email -> System.out.println(email.getContent()));
}
return "任务执行完毕!";
}
}
邮件类
@Data
@NoArgsConstructor
@AllArgsConstructor
public class Email {
// 邮件类型
private int type;
// 邮件内容
private String content;
}
邮件类型枚举类
public enum EmailType {
FANS_EMAIL(1, "粉丝邮件"),
SLANDER_EMAIL(2, "诽谤邮件"),
COOPERATE_EMAIL(3, "业务合作邮件"),
GARBAGE_EMAIL(99, "垃圾邮件");
public int type;
public String remark;
EmailType(int type, String remark) {
this.type = type;
this.remark = remark;
}
}
责任链模式测试类
public class ChainTest {
// 初始化待处理邮件
private static List<Email> emails = Lists.newArrayList(new Email(EmailType.FANS_EMAIL.type, "我是粉丝A"),
new Email(EmailType.COOPERATE_EMAIL.type, "我要找你们合作"),
new Email(EmailType.GARBAGE_EMAIL.type, "我是垃圾邮件"),
new Email(EmailType.FANS_EMAIL.type, "我是粉丝B"));
public static void main(String[] args) {
// 初始化处理类
AbstractProcessor ceoProcessor = new CeoProcessor();
AbstractProcessor lawProcessor = new LawProcessor();
AbstractProcessor businessProcessor = new BusinessProcessor();
AbstractProcessor garbageProcessor = new GarbageProcessor();
// 设置责任链条
ceoProcessor.setNextProcessor(lawProcessor);
lawProcessor.setNextProcessor(businessProcessor);
businessProcessor.setNextProcessor(garbageProcessor);
// 开始处理邮件
ceoProcessor.handleMessage(emails);
}
}
状态模式
定义:允许对象中在内部状态改变时改变它的行为,对象看起来好像修改了它的类(让投币的动作处理投币状态的扭转)
状态接口
public interface State {
// 投入硬币操作
void insertQuarter();
// 退出硬币操作
void ejectQuarter();
// 扭转曲柄操作
void turnCrank();
// 发放糖果操作
void dispense();
}
已投放钱币状态类实现状态接口
public class HasQuarterState implements State {
private GumballMachine gumballMachine;
public HasQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("您已经投入钱币!无须再次投入钱币!");
}
@Override
public void ejectQuarter() {
System.out.println("退款成功!");
gumballMachine.setState(gumballMachine.getNoQuarterState()); // 状态流转
}
@Override
public void turnCrank() {
System.out.println("正在出货中,请稍等");
gumballMachine.setState(gumballMachine.getSoldState()); // 状态流转
}
@Override
public void dispense() {
System.out.println("你还没有扭转曲柄,糖果不可以发放!");
}
}
没有投币状态类实现状态接口
public class NoQuarterState implements State {
private GumballMachine gumballMachine;
public NoQuarterState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("投入钱币成功!");
gumballMachine.setState(gumballMachine.getHasQuarterState()); // 状态流转
}
@Override
public void ejectQuarter() {
System.out.println("你还没有投入钱币,不能退回钱币!");
}
@Override
public void turnCrank() {
System.out.println("你还没有投入钱币,不能扭转曲柄!");
}
@Override
public void dispense() {
System.out.println("你还没有投入钱币,糖果不可以发放!");
}
}
糖果售罄类实现状态接口
public class SoldOutState implements State {
private GumballMachine gumballMachine;
public SoldOutState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("糖果已经售罄。不能投入钱币");
}
@Override
public void ejectQuarter() {
System.out.println("退回钱币成功!");
}
@Override
public void turnCrank() {
System.out.println("糖果已经售罄。不能扭转曲柄!");
}
@Override
public void dispense() {
System.out.println("糖果已经售罄。糖果无法出售!");
}
}
糖果售卖类实现状态接口
public class SoldState implements State {
private GumballMachine gumballMachine;
public SoldState(GumballMachine gumballMachine) {
this.gumballMachine = gumballMachine;
}
@Override
public void insertQuarter() {
System.out.println("糖果正在出货中,请稍等。无须再次投入钱币!");
}
@Override
public void ejectQuarter() {
System.out.println("糖果正在出货中,请稍等。不能退回钱币!");
}
@Override
public void turnCrank() {
System.out.println("糖果正在出货中,请稍等。不需要再次扭转曲柄!");
}
@Override
public void dispense() {
if (gumballMachine.getCount() > 0) {
System.out.println("糖果正在出货中,请稍等!");
gumballMachine.releaseBall();
gumballMachine.setState(gumballMachine.getNoQuarterState()); // 状态流转
} else {
System.out.println("糖果库存不足,无法出货!");
gumballMachine.setState(gumballMachine.getSoldOutState()); // 状态流转
}
}
}
状态模式测试类
public class StateTest {
public static void main(String[] args) {
System.out.println("-----向糖果机中放入1枚糖果-----");
GumballMachine machine = new GumballMachine(1);
System.out.println("-----第一次购买糖果-----");
machine.insertQuarter();
machine.ejectQuarter();
machine.turnCrank();
System.out.println("-----第二次购买糖果-----");
machine.insertQuarter();
machine.turnCrank();
System.out.println("-----第三次购买糖果-----");
machine.insertQuarter();
machine.turnCrank();
machine.ejectQuarter();
}
}
观察者模式
定义:定义了对象之间一对多的依赖,这样以来,当一个对象改变状态时,它的所有以来都会收到通知并自动更新
中介者模式
定义:使用中介者模式来集中相关对象之间复杂的沟通和控制方式
中介者
public class Mediator {
protected Purchase purchase;
protected Sale sale;
protected Stock stock;
public Mediator() {
purchase = new Purchase(this);
sale = new Sale(this);
stock = new Stock(this);
}
/** 采购电脑 */
public void purchaseByComputer(int num) {
int saleStatus = sale.getSaleStatus();
// 如果销售情况不好(即:没有超过80台),则采购总数减半
String msg = "";
if (saleStatus <= 80) {
num = num / 2;
msg = "由于销售不佳,采购总数减半,";
}
System.out.println(msg + "原有库存电脑" + stock.getStockNumber() + "台,现采购电脑" + num + "台");
stock.increaseComputer(num);
}
/** 销售电脑 */
public void saleSellComputer(int num) {
// 如果库存数量不足,则采购2倍的num电脑数,暂时只售卖库存中有的数量
int stockNum;
if ((stockNum = stock.getStockNumber()) < num) {
purchase.buyComputer(2*num);
num = stockNum;
}
stock.decreaseComputer(num);
}
/** 折价销售电脑 */
public void saleOffSale() {
System.out.println("折价销售电脑");
}
/** 清理库存 */
public void stockClear() {
sale.offSale(); // 折价销售电脑
purchase.refuseBuyComputer(); // 不要采购电脑
}
}
抽象功能
public abstract class AbstractColleague {
protected Mediator mediator;
public AbstractColleague(Mediator mediator) {
this.mediator = mediator;
}
}
销售功能
public class Sale extends AbstractColleague {
public Sale(Mediator mediator) {
super(mediator);
}
/** 销售电脑 */
public void sellComputer(int number) {
super.mediator.saleSellComputer(number);
System.out.println("销售电脑" + number + "台");
}
/** 获得销售情况(即:售卖了多少台电脑) */
public int getSaleStatus() {
// 模拟销售数量
int sellNumber = new Random(System.currentTimeMillis()).nextInt(100);
System.out.println("电脑的销售情况为:" + sellNumber + "台");
return sellNumber;
}
/** 折价处理 */
public void offSale() {
super.mediator.saleOffSale();
}
}
库存功能
public class Stock extends AbstractColleague {
private static int COMPUTER_NUM = 100;
public Stock(Mediator mediator) {
super(mediator);
}
/** 增加库存 */
public void increaseComputer(int number) {
COMPUTER_NUM += number;
System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
}
/** 减少库存 */
public void decreaseComputer(int number) {
COMPUTER_NUM -= number;
System.out.println("电脑的库存数量为:" + COMPUTER_NUM);
}
/** 获得当前库存 */
public int getStockNumber() {
return COMPUTER_NUM;
}
/** 清理库存 */
public void clearStock() {
System.out.println("清理库存数量为:" + COMPUTER_NUM);
super.mediator.stockClear();
}
}
> 采购功能
```java
public class Purchase extends AbstractColleague {
public Purchase(Mediator mediator) {
super(mediator);
}
/** 采购电脑 */
public void buyComputer(int num) {
System.out.println();
super.mediator.purchaseByComputer(num);
}
/** 不再采购电脑 */
public void refuseBuyComputer() {
System.out.println("不再采购电脑!");
}
}
中介者模式测试类
public class MediatorTest {
public static void main(String[] args) {
Mediator mediator = new Mediator();
System.out.println("--------采购人员采购电脑--------");
Purchase purchase = new Purchase(mediator);
purchase.buyComputer(100);
System.out.println("--------销售人员销售电脑--------");
Sale sale = new Sale(mediator);
sale.sellComputer(1);
System.out.println("--------库房人员清库处理--------");
Stock stock = new Stock(mediator);
stock.clearStock();
}
}
迭代器模式
定义:提供一个方法顺序访问一个聚合对象中的各个元素,而又不暴露其内部的表示
访问者模式
定义:表示一个作用于某个对象结构中的各元素的操作。它使你可以在不改变各元素的类的前提下定义作用于这些元素的新操作
电脑类
public class Computer {
private ComputerComponent memory;
private ComputerComponent cpu;
public Computer() {
memory = new Memory();
cpu = new Cpu();
}
/**
* 攒机方法
*
* @Visitor 买电脑的客户角色
*/
public void buildComputer(Visitor visitor) {
// 买cpu
cpu.accept(visitor);
// 买内存
memory.accept(visitor);
}
}
访问者接口
public interface Visitor {
void visitorCpu(Cpu cpu);
void visitorMemory(Memory memory);
int price();
String visiterName();
}
个人用户
public class PersonVisitor implements Visitor {
// 总售价
public int totalPrice;
@Override
public void visitorCpu(Cpu cpu) {
totalPrice += cpu.price();
}
@Override
public void visitorMemory(Memory memory) {
totalPrice += memory.price();
}
@Override
public int price() {
return totalPrice;
}
@Override
public String visiterName() {
return "个人用户";
}
}
学生用户
public class StudentVisitor implements Visitor {
// 总售价
public int totalPrice;
@Override
public void visitorCpu(Cpu cpu) {
totalPrice += cpu.price() * 0.8;
}
@Override
public void visitorMemory(Memory memory) {
totalPrice += memory.price() * 0.9;
}
@Override
public int price() {
return totalPrice;
}
@Override
public String visiterName() {
return "学生用户";
}
}
公司大客户用户
public class CompanyVisitor implements Visitor {
// 总售价
public int totalPrice;
@Override
public void visitorCpu(Cpu cpu) {
totalPrice += cpu.price() * 0.5;
}
@Override
public void visitorMemory(Memory memory) {
totalPrice += memory.price() * 0.4;
}
@Override
public int price() {
return totalPrice;
}
@Override
public String visiterName() {
return "公司大客户";
}
}
电脑组件接口
public interface ComputerComponent {
// 售价
int price();
// 硬件版本
String version();
// 描述
String desc();
void accept(Visitor visitor);
}
CPU
public class Cpu implements ComputerComponent {
// 全国标准售价
public int price = 100;
@Override
public int price() {
return 100;
}
@Override
public String version() {
return "v1";
}
@Override
public String desc() {
return "英特尔CPU";
}
@Override
public void accept(Visitor visitor) {
visitor.visitorCpu(this);
}
}
内存
public class Memory implements ComputerComponent {
// 全国标准售价
public int price = 400;
@Override
public int price() {
return price;
}
@Override
public String version() {
return "v4";
}
@Override
public String desc() {
return "金士顿内存";
}
@Override
public void accept(Visitor visitor) {
visitor.visitorMemory(this);
}
}
访问者模式测试类
public class VisitorTest {
public static void main(String[] args) {
Computer computer = new Computer();
Visitor personVisitor = new PersonVisitor();
Visitor studentVisitor = new StudentVisitor();
Visitor companyVisitor = new CompanyVisitor();
computer.buildComputer(personVisitor);
System.out.println(String.format("针对%s,每台电脑售价为:%s元", personVisitor.visiterName(), personVisitor.price()));
computer.buildComputer(studentVisitor);
System.out.println(String.format("针对%s,每台电脑售价为:%s元", studentVisitor.visiterName(), studentVisitor.price()));
computer.buildComputer(companyVisitor);
System.out.println(String.format("针对%s,每台电脑售价为:%s元", companyVisitor.visiterName(), companyVisitor.price()));
}
}
备忘录模式
定义:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保持这个状态,这样以后就可以将该对象恢复到原先保存到状态。当你需要让对象返回之前到状态时(例如:撤销),就使用备忘录模式
文件类
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Document {
// 文档的内容
private String content;
public void print() {
System.out.println("content=" + content);
}
}
文档内容
@AllArgsConstructor
@NoArgsConstructor
@Data
public class Memento {
// 文档内容
public String content;
}
备忘录管理类
public class MementoManager {
// 记录备忘录信息
private Stack<Memento> mementoStack = new Stack<>();
// 保存备忘录
public void save(Document document) {
Memento memento = new Memento(document.getContent());
mementoStack.add(memento);
}
// 撤销操作ctrl+z
public Document cancel() {
Memento memento = mementoStack.pop();
Document document = new Document();
document.setContent(memento.getContent());
return document;
}
}
备忘录测试类
public class MementoTest {
public static void main(String[] args) {
MementoManager mementoManager = new MementoManager();
System.out.println("-----执行文档修改操作-----");
Document document = new Document();
document.setContent("a");
document.print();
mementoManager.save(document);
document.setContent("b");
document.print();
mementoManager.save(document);
document.setContent("c"); // 修改后,发现写错了,想要回撤到上一个保存点
document.print();
System.out.println("-----执行第一次撤销操作-----");
document = mementoManager.cancel();
document.print();
System.out.println("-----执行第二次撤销操作-----");
document = mementoManager.cancel();
document.print();
}
}