十大设计模式总结版
- 十大设计模式
- [1.Singleton 单例模式](#1.Singleton 单例模式)
- [2.Proxy 代理模式](#2.Proxy 代理模式)
- 3.Adapter适配器模式
- 4.Chain责任链模式
- [5.Simple Factory简单工厂模式](#5.Simple Factory简单工厂模式)
- [6.Factory Method工厂方法模式](#6.Factory Method工厂方法模式)
- [7.Template Method模板方法模式](#7.Template Method模板方法模式)
- [8.Decorator 装饰器模式](#8.Decorator 装饰器模式)
- [9.Observer 观察者模式](#9.Observer 观察者模式)
- [10.Strategy 策略模式](#10.Strategy 策略模式)
十大设计模式
主要是对前面的设计模式进行一个总结,主要掌握以下十大设计模式,其他的设计模式后面的在慢慢熟悉。
1.Singleton 单例模式
1.1单例模式的实现思路
- 静态化实例对象,让实例对象与Class对象互相绑定,通过Class类对象就可以直接访问
- 私有化构造方法,禁止通过构造方法来创建多个实例
- 创建公共的静态方法,通过该静态方法来调用私有化构造方法来创建对象,并将其保存在一个静态成员变量中,用来返回该类的唯一实例。
1.2饿汉类
java
public class Hungry {
//1.创建一个静态实例对象
private static Hungry instance = new Hungry();
//2. 私有化构造方法
private Hungry() {}
//3.在静态方法中创建实例对象,并将其返回
public static Hungry getInstance() {
return instance;
}
}
1.2.1优点
- JVM层面的线程安全
- 造成空间的浪费
1.3懒汉类
java
package com.technologystatck.designpattern.modereview.singleton;
public class Lazy {
//1.创建一个静态实例对象,允许为空
private static Lazy instance = null;
//2.私有化构造方法
private Lazy() {
}
//3.在静态方法中实例化对象,并将其返回
public static Lazy getInstance() {
if (instance == null) {
instance = new Lazy();
}
return instance;
}
//4.若为线程安全可以使用synchronized关键字
public static synchronized Lazy getSynInstance() {
if (instance == null) {
instance = new Lazy();
}
return instance;
}
}
1.3.1优点
- 节省空间,用到的时候再创建实例对象
- 线程不安全
- 若添加了synchronized关键字,对同步进行操作,有很严重的性能问题
1.4双重检查锁
java
package com.technologystatck.designpattern.modereview.singleton;
public class DoubleCheckLocking {
//1.创建实例对象
private static volatile DoubleCheckLocking instance=null;
//2.私有化构造方法
private DoubleCheckLocking(){
}
//3.使用静态方法中创建对象
public static DoubleCheckLocking getInstance(){
//先判断实例是否存在
if(instance == null){
//加锁创建实例
synchronized (DoubleCheckLocking.class){
//再次判断,若拿了锁很有可能出现还没来得及初始化就释放了锁
//导致可能创建多个实例对象
if(instance == null){
instance = new DoubleCheckLocking();
}
}
}
return instance;
}
}
-
使用volatile关键字修饰instance变量
private static volatile DoubleCheckLocking instance=null;
1.4.1优点
- 使用双重检查锁进行多层判断,保证了对象实例化
- 使用volatile关键字禁止了JVM的指令重排序
1.5静态内部类
java
package com.technologystatck.designpattern.modereview.singleton;
public class StaticInner {
//1.通过静态内部类实例化对象
private static class StaticInnerSingleton{
private static StaticInner instance = new StaticInner();
}
//2.私有化构造方法
private StaticInner(){
}
//3.创建静态方法返回实例化的对象
public static StaticInner getInstance(){
return StaticInnerSingleton.instance;
}
}
1.5.1优点
- 没有加锁,线程安全
- 即时用再加载,并发性能高
1.6枚举类
java
package com.technologystatck.designpattern.modereview.singleton;
enum Enums {
//创建枚举类的实例
INSTANCE;
//对单例对象的进行相关操作的方法
public void doSingleton(){
System.out.println("正在执行枚举类实现的单例对象的方法");
}
}
1.6.1优点
- 不需要考虑序列化问题
- 不需要考虑反射问题
1.7ThreadLocal
java
package com.technologystatck.designpattern.modereview.singleton;
public class ThreadLocals {
//1.初始化ThreadLocal,同时实例化对象
private static ThreadLocal threadInstance = new ThreadLocal();
private static ThreadLocals instance=null;
//2.使用静态方法将实例化的对象返回
public static ThreadLocals getInstance(){
if(threadInstance.get()==null){
createInstance();
}
return instance;
}
//3.创建实例化对象的方法
private static final void createInstance(){
synchronized (ThreadLocals.class){
if(instance==null){
instance=new ThreadLocals();
}
}
//设置非空值,以便后续判断不再执行创建操作
threadInstance.set(threadInstance);
}
//4.调用remove方法清除当前线程的threadInstance变量的值
public static void remove(){
threadInstance.remove();
}
}
1.7.1优点
- 保证了线程安全
- 即时用再初始化
2.Proxy 代理模式
2.1静态代理
2.1.1静态代理的实现思路
- 静态代理需要先定义接口
- 被代理对象与代理对象一起实现相同的接口
- 通过调用相同的方法来调用目标对象的方法
-
小明想要购买一套房子,他决定寻求一家房屋中介来帮助他找到一个面积超过100平方米的房子,只有符合条件的房子才会被传递给小明查看。
javapackage com.technologystatck.designpattern.modereview.proxy; public class StaticProxy { public static void main(String[] args) { House house1 = new House("武汉", 101); House house2 = new House("上海", 201); House house3 = new House("天津", 81); House house4 = new House("深圳", 88); HouseProxy houseProxy = new HouseProxy(); houseProxy.tradeHouse(house1); houseProxy.tradeHouse(house2); houseProxy.tradeHouse(house3); houseProxy.tradeHouse(house4); } } //1.定义抽象接口 //房屋交易接口 interface HouseTransaction{ //定义交易房子的方法 void tradeHouse(House house); } //2.定义被代理对象 class Seller implements HouseTransaction{ @Override public void tradeHouse(House house) { System.out.println("我是卖家,我在"+house.getAddress()+"卖"+house.getArea()+"平房子"); } } //3.定义代理对象 //相当于房屋中介 class HouseProxy implements HouseTransaction{ @Override public void tradeHouse(House house) { if(house.getArea()>100){ System.out.println("我是小明委托的中介,我在"+house.getAddress()+"看"+house.getArea()+"平房子"); } } } //定义房子类 class House{ private String address; private int area; public House() { } public House(String address, int area) { this.address = address; this.area = area; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getArea() { return area; } public void setArea(int area) { this.area = area; } @Override public String toString() { return "House{" + "address='" + address + '\'' + ", area=" + area + '}'; } }
2.1.2优点
- 静态代理在不改变目标对象的前提下,实现了对目标对象的功能扩展。
2.2动态代理
2.2.1动态代理的实现思路
- 需要代理类实现接口,使用Proxy.newProxyInstance方法生成代理类
- 实现InvocationHandler中的invoke方法,实现增强功能
ClassLoader loader
:指定当前目标对象使用类加载器,获取加载器的方法是固定的。Class<?>[] interfaces
:目标对象实现的接口的类型,使用泛型方式确认类型。InvocationHandler h
:事件处理,执行目标对象的方法时,会触发事件处理器的方法,会把当前执行目标对象的方法作为参数传入
-
小明想要购买一套房子,他决定寻求一家房屋中介来帮助他找到一个面积超过100平方米的房子,只有符合条件的房子才会被传递给小明查看。买房还需要一些手续,他需要房屋中介来帮助他履行完这些手续。
javapackage com.technologystatck.designpattern.modereview.proxy; import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.ArrayList; public class StaticProxy { public static void main(String[] args) { House house1 = new House("北京", 101); House house2 = new House("上海", 201); House house3 = new House("广州", 81); House house4 = new House("深圳", 88); ArrayList<House> houses = new ArrayList<>(); houses.add(house1); houses.add(house2); houses.add(house3); houses.add(house4); HouseProxy houseProxy=null; for (House house : houses) { HouseTransaction target = new Seller(); HouseTransaction proxy = (HouseTransaction) new HouseProxy(target).getProxy(); if(house.getArea()>100){ proxy.tradeHouse(house); proxy.serviceCharges(house); } } } } //1.定义抽象接口 //房屋交易接口 interface HouseTransaction{ //定义交易房子的方法 void tradeHouse(House house); void serviceCharges(House house); } //2.定义被代理对象 class Seller implements HouseTransaction{ @Override public void tradeHouse(House house) { System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子"); } @Override public void serviceCharges(House house) { System.out.println("可以交接"+house.getAddress()+"的"+house.getArea()+"平房子手续"); } } //3.定义代理对象 //相当于房屋中介 class HouseProxy{ private Object target; public HouseProxy(Object o) { this.target = o; } public Object getProxy(){ return Proxy.newProxyInstance(this.getClass().getClassLoader(), target.getClass().getInterfaces(), new InvocationHandler() { //使用Proxy.newProxyInstance方法生成代理对象, //实现InvocationHandler中的 invoke方法, //在invoke方法中通过反射调用代理类的方法,并提供增强方法 @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.println("House Proxy动态代理"); Object invoke = method.invoke(target, args); return invoke; } }); } } //定义房子类 class House{ private String address; private int area; public House() { } public House(String address, int area) { this.address = address; this.area = area; } public String getAddress() { return address; } public void setAddress(String address) { this.address = address; } public int getArea() { return area; } public void setArea(int area) { this.area = area; } @Override public String toString() { return "House{" + "address='" + address + '\'' + ", area=" + area + '}'; } }
优点:不需要实现接口,但是目标对象需要实现接口
2.3Cglib代理
2.3.1Cglib代理的实现思路
- 通过enhancer来生成代理类,通过实现MethodInterceptor接口,并实现其中的intercept方法
- 在该方法中可以添加增强方法,并利用反射Method或MethodProxy继承类来调用原方法
java
package com.technologystatck.designpattern.modereview.proxy;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
import java.util.ArrayList;
public class CglibProxy {
public static void main(String[] args) {
House house1 = new House("北京", 101);
House house2 = new House("上海", 201);
House house3 = new House("广州", 81);
House house4 = new House("深圳", 88);
ArrayList<House> houses = new ArrayList<>();
houses.add(house1);
houses.add(house2);
houses.add(house3);
houses.add(house4);
for (House house : houses) {
HouseTransaction proxyInstance = (HouseTransaction) new HouseProxy().getProxyInstance(Seller.class);
if(house.getArea()>100){
proxyInstance.tradeHouse(house);
proxyInstance.serviceCharges(house);
}
}
}
}
//1.定义抽象接口
//房屋交易接口
interface HouseTransaction{
//定义交易房子的方法
void tradeHouse(House house);
void serviceCharges(House house);
}
//2.定义被代理对象
class Seller implements HouseTransaction{
@Override
public void tradeHouse(House house) {
System.out.println("有一个"+house.getAddress()+"的"+house.getArea()+"平房子");
}
@Override
public void serviceCharges(House house) {
System.out.println("可以交接"+house.getAddress()+"的"+house.getArea()+"平房子手续");
}
}
//3.定义代理对象
//相当于房屋中介
class HouseProxy implements MethodInterceptor {
//给目标对象创建一个代理对象
public Object getProxyInstance(Class c){
//1.工具类
Enhancer enhancer = new Enhancer();
//2.设置父类
enhancer.setSuperclass(c);
//3.设置回调函数
enhancer.setCallback(this);
//4.创建子类(代理对象)
return enhancer.create();
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("Cglib代理处理");
Object object = methodProxy.invokeSuper(o, objects);
return object;
}
}
//定义房子类
class House{
private String address;
private int area;
public House() {
}
public House(String address, int area) {
this.address = address;
this.area = area;
}
public String getAddress() {
return address;
}
public void setAddress(String address) {
this.address = address;
}
public int getArea() {
return area;
}
public void setArea(int area) {
this.area = area;
}
@Override
public String toString() {
return "House{" +
"address='" + address + '\'' +
", area=" + area +
'}';
}
}
Cglib的maven依赖
java
<dependency>
<groupId>cglib</groupId>
<artifactId>cglib</artifactId>
<version>3.3.0</version>
</dependency>
2.3.2优点
- 无需代理类实现接口
3.Adapter适配器模式
3.1类的适配器模式的实现思路(继承实现)
- 定义期望获得的功能接口,完成扩展
- 定义现有的接口,也就是需要被适配的接口
- 定义现有接口的具体实现类,需要实现现有接口
- 定义一个类适配器,通过继承现有接口来完成现有接口的扩展
小明购买了一台新电脑,该电脑使用 TypeC 接口,他已经有了一个USB接口的充电器和数据线,为了确保新电脑可以使用现有的USB接口充电器和数据线,他购买了一个TypeC到USB的扩展坞。使用适配器模式设计并实现这个扩展坞系统,确保小明的新电脑既可以通过扩展坞使用现有的USB接口充电线和数据线,也可以使用TypeC接口充电。
java
package com.technologystatck.designpattern.modereview.adapter;
public class ClassAdapter {
public static void main(String[] args) {
//实例化适配器,相当于就可以通过适配器完成两种接口充电
AdapterCharge adapterCharge = new AdapterCharge();
adapterCharge.chargeUseUSB();
adapterCharge.chargeUseTypeC();
}
}
//定义一个期望获得的功能接口
interface TypeCTarget{
//使用TypeC接口充电
void chargeUseTypeC();
}
//定义现有的USB接口
interface USBTarget{
//使用USB接口充电
void chargeUseUSB();
}
//现有的接口具体实现类,USB
class ConcreteUSBTarget implements USBTarget{
@Override
public void chargeUseUSB() {
System.out.println("正在通过USB接口充电");
}
}
//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展
class AdapterCharge extends ConcreteUSBTarget implements TypeCTarget{
//完成USB接口充电
@Override
public void chargeUseUSB() {
super.chargeUseUSB();
}
//完成TypeC接口充电
@Override
public void chargeUseTypeC() {
System.out.println("可以使用TypeC接口充电");
}
}
3.2对象的适配器模式(扩展实现)
-
定义期望获得的功能接口,完成扩展
-
定义现有的接口,也就是需要被适配的接口
-
定义现有接口的具体实现类,需要实现现有接口
-
定义一个类适配器,通过继承现有接口,
持有现有接口类一个实例,并完成其扩展功能,以此来实现目标接口
java
package com.technologystatck.designpattern.modereview.adapter;
public class ObjectAdapter {
public static void main(String[] args) {
USBTarget concreteUSBTarget = new ConcreteUSBTarget();
AdapterCharge adapterCharge = new AdapterCharge(concreteUSBTarget);
adapterCharge.chargeUseTypeC();
}
}
//定义一个期望获得的功能接口--使用TypeC接口充电
interface TypeCTarget{
//使用TypeC接口充电
void chargeUseTypeC();
}
//定义现有的USB接口
interface USBTarget{
//使用USB接口充电
void chargeUseUSB();
}
//现有的接口具体实现类,USB
class ConcreteUSBTarget implements USBTarget{
@Override
public void chargeUseUSB() {
System.out.println("正在通过USB接口充电");
}
}
//类适配器,相当于TypeC到USB充电的扩展坞
//继承现有接口来完成对现有接口的扩展,持有实例完成扩展功能
class AdapterCharge implements TypeCTarget{
private USBTarget usbTarget;
public AdapterCharge() {
}
public AdapterCharge(USBTarget usbTarget) {
this.usbTarget = usbTarget;
}
//在现有功能的基础上扩展功能
@Override
public void chargeUseTypeC() {
usbTarget.chargeUseUSB();
System.out.println("可以使用TypeC接口充电");
}
}
3.3优点
- 可以让任何两个没有关联的类一起运行
- 提高了类的复用,将现有接口实现类进行隐藏
4.Chain责任链模式
4.1责任链的实现思路
- 定义请求对象,含有很多属性,表示一个请求
- 定义抽象处理者,主要用于处理请求,同时设置方法参数来保存其他的处理者
- 定义具体处理者,实现抽象处理者接口,处理自己负责的请求,并且实例化抽象处理者,可以访问到下一个处理者,若能处理请求则在此处处理,若不能处理请求且处理者参数不为空则将请求发送给下一个处理者
小明所在的公司请假需要在OA系统上发布申请,整个请求流程包括多个处理者,每个处理者负责处理不同范围的请假天数,如果一个处理者不能处理请求,就会将请求传递给下一个处理者,请你实现责任链模式,可以根据请求天数找到对应的处理者。
审批责任链由主管(Supervisor), 经理(Manager)和董事(Director)组成,他们分别能够处理3天、7天和10天的请假天数。如果超过10天,则进行否决。
java
package com.technologystatck.designpattern.modereview.chainofresponsibility;
public class Chain {
public static void main(String[] args) {
Request requestObject1 = new Request("张三","病假",3);
Request requestObject2 = new Request("李四","公假",6);
Request requestObject3 = new Request("王五","事假",9);
Request requestObject4 = new Request("赵六","事假",12);
//定义责任链对象
Supervisor supervisor = new Supervisor();
Manager manager = new Manager(supervisor);
Director director = new Director(manager);
//执行
supervisor.handlerRequest(requestObject1);
manager.handlerRequest(requestObject2);
director.handlerRequest(requestObject3);
director.handlerRequest(requestObject4);
}
}
//定义请求对象
class Request{
//请求人
String name;
//请求事件
String requestStr;
//请求天数
int day;
public Request(String name, String requestStr, int day) {
this.name = name;
this.requestStr = requestStr;
this.day = day;
}
public String getName() {
return name;
}
public String getRequestStr() {
return requestStr;
}
public int getDay() {
return day;
}
}
//定义抽象处理者
interface CurrentHandler{
//设置处理当前请求的方法
void handlerRequest(Request request);
}
//定义具体处理者-主管
class Supervisor implements CurrentHandler{
//设置条件天数
private static final int APPROVE_DAY=3;
//设置下一个处理者
private CurrentHandler nextHandler;
public Supervisor() {
}
public Supervisor(CurrentHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handlerRequest(Request request) {
if(request.getDay()<=APPROVE_DAY){
System.out.println(request.getName()+" Approved by Supervisor.");
}else if(nextHandler !=null){
nextHandler.handlerRequest(request);
}else{
System.out.println(request.getName()+" No Approve by Supervisor.");
}
}
}
//定义具体处理者-主管
class Manager implements CurrentHandler{
//设置条件天数
private static final int APPROVE_DAY=7;
//设置下一个处理者
private CurrentHandler nextHandler;
public Manager(CurrentHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handlerRequest(Request request) {
if(request.getDay()<=APPROVE_DAY){
System.out.println(request.getName()+" Approved by Manager.");
}else if(nextHandler !=null){
nextHandler.handlerRequest(request);
}else{
System.out.println(request.getName()+" No Approve by Manager.");
}
}
}
//定义具体处理者-董事
class Director implements CurrentHandler{
//设置条件天数
private static final int APPROVE_DAY=10;
//设置下一个处理者
private CurrentHandler nextHandler;
public Director(CurrentHandler nextHandler) {
this.nextHandler = nextHandler;
}
@Override
public void handlerRequest(Request request) {
if(request.getDay()<=APPROVE_DAY){
System.out.println(request.getName()+" Approved by Director.");
}else if(nextHandler !=null){
nextHandler.handlerRequest(request);
}else{
System.out.println(request.getName()+" No Approve by Director.");
}
}
}
4.2优点
- 将多个处理器组合在一起,依次处理请求
- 添加新的处理器或者重新排列处理器非常容易
5.Simple Factory简单工厂模式
5.1简单工厂的实现思路
- 定义简单工厂类,用于实现所有实例对象的内部逻辑,其中创建产品的方法可以被外界调用,创建所需的产品对象
- 定义抽象产品类,是工厂类创建的所有对象的父类,封装了各种产品对象的公有放啊,
- 定义具体产品类,每一个具体产品类都继承自抽象产品类,需要实现抽象产品类的方法
小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。
java
package com.technologystatck.designpattern.modereview.simplefactory;
import java.util.ArrayList;
import java.util.List;
public class SimpleFactory {
public static void main(String[] args) {
BlockFactorySystem blockFactorySystem = new BlockFactorySystem();
blockFactorySystem.BuildBlocks("redirect",2);
blockFactorySystem.BuildBlocks("square",2);
//创建圆形
BlockFactory.factoryCreateBlock("redirect").createBlock();
//创建方形
BlockFactory.factoryCreateBlock("square").createBlock();
}
}
//定义抽象产品类
abstract class Product{
//创建积木方法
abstract void createBlock();
}
//定义具体产品类--圆形积木
class RedirectBlock extends Product{
@Override
void createBlock() {
System.out.println("创建圆形积木");
}
}
//定义具体产品类--方形积木
class SquareBlock extends Product{
@Override
void createBlock() {
System.out.println("创建方形积木");
}
}
//定义工厂类
class BlockFactory{
public static Product factoryCreateBlock(String type){
if(type.equals("redirect")){
return new RedirectBlock();
}else if(type.equals("square")){
return new SquareBlock();
}else{
throw new IllegalArgumentException("无效的积木");
}
}
}
//积木工厂系统
class BlockFactorySystem{
//定义集合存放积木信息
private List<Product> products=new ArrayList();
//创建积木方法
public void BuildBlocks(String type,int nums){
for(int i=0;i<nums;i++){
if(type.equals("redirect") || type.equals("square"))
BlockFactory.factoryCreateBlock(type).createBlock();
}
}
}
6.Factory Method工厂方法模式
6.1工厂方法的实现思路
- 定义抽象工厂接口,用于创建一族产品的方法,每个方法对应一种产品
- 定义具体工厂类,实现抽象工厂接口,用于创建一组具体产品的对象
- 定义抽象产品接口,为每种产品声明接口,在抽象产品接口中声明产品所有的业务方法
- 定义具体产品类,定义了具体工厂生产的具体产品对象,实现抽象产品接口中声明的业务方法
小明家有两个工厂,一个用于生产圆形积木,一个用于生产方形积木,请你帮他设计一个积木工厂系统,记录积木生产的信息。
java
package com.technologystatck.designpattern.modereview.factorymethod;
import java.util.ArrayList;
import java.util.List;
public class FactoryMethod {
public static void main(String[] args) {
new BlockFactorySystem().BuildBlocks(new RedirectBlockFactory(),3);
new BlockFactorySystem().BuildBlocks(new SquareBlockFactory(),2);
System.out.println("=====================");
RedirectBlockFactory redirectBlockFactory = new RedirectBlockFactory();
redirectBlockFactory.createBlock().createBlockProduct();
BlockProduct block = new SquareBlockFactory().createBlock();
block.createBlockProduct();
}
}
//定义抽象产品接口
interface BlockProduct{
void createBlockProduct();
}
//定义具体产品实现类-圆形积木
class RedirectBlock implements BlockProduct{
@Override
public void createBlockProduct() {
System.out.println("创建圆形积木");
}
}
//定义具体产品实现类-方形积木
class SquareBlock implements BlockProduct{
@Override
public void createBlockProduct() {
System.out.println("创建方形积木");
}
}
//定义抽象工厂接口
interface BlockFactory{
//创建积木
BlockProduct createBlock();
}
//定义具体工厂实现类-圆形积木
class RedirectBlockFactory implements BlockFactory{
@Override
public BlockProduct createBlock() {
return new RedirectBlock();
}
}
//定义具体工厂实现类-方形积木
class SquareBlockFactory implements BlockFactory{
@Override
public BlockProduct createBlock() {
return new SquareBlock();
}
}
//定义工厂系统
class BlockFactorySystem{
private List<BlockProduct> blockProducts=new ArrayList<BlockProduct>();
public void BuildBlocks(BlockFactory factory,int nums){
for(int i=0;i<nums;i++){
BlockProduct block = factory.createBlock();
blockProducts.add(block);
block.createBlockProduct();
}
}
}
6.2优点
- 工厂方法只有一个抽象产品类和一个抽象工厂类,但可以派生出多个具体产品类和具体工厂类
- 每个具体工厂类只能创建一个具体产品类的实例
7.Template Method模板方法模式
7.1模板方法的实现思路
-
定义一个抽象模板类,负责给出算法的轮廓和骨架,由一个模板方法和若干个基本方法构成
-
定义模板方法:定义了算法的骨架,按某种顺序调用其包含的基本方法
-
定义基本方法,是实现算法各个步骤的方法,是模板方法的组成部分
-
抽象方法:由抽象类声明、由其具体子类实现
-
具体方法:由一个抽象类或具体类声明并实现,其子类可以进行覆盖也可以直接继承
-
钩子方法:在抽象类中已经实现,包括用于判断的逻辑方法和需要子类重写的空方法两种
用于判断的逻辑方法,方法名一般为isXxx,返回值类型为boolean类型
-
-
-
可以定义多个具体模板类,实现抽象模板类中所定义的抽象方法和钩子方法,是顶级逻辑的组成步骤
小明喜欢品尝不同类型的咖啡,她发现每种咖啡的制作过程有一些相同的步骤,他决定设计一个简单的咖啡制作系统,使用模板方法模式定义咖啡的制作过程。系统支持两种咖啡类型:美式咖啡(American Coffee)和拿铁(Latte)。
咖啡制作过程包括以下步骤:
- 研磨咖啡豆 Grinding coffee beans
- 冲泡咖啡 Brewing coffee
- 添加调料 Adding condiments
其中,美式咖啡和拿铁的调料添加方式略有不同, 拿铁在添加调料时需要添加牛奶Adding milk
java
package com.technologystatck.designpattern.modereview.template;
public class Template {
public static void main(String[] args) {
CoffeeTemplate american = new American();
CoffeeTemplate latte = new Latte();
CoffeeTemplate milk = new Milk();
//通过钩子方法进行判断
if (!american.isMilk()) {
american.makeCoffee();
}
if (!latte.isMilk()) {
latte.makeCoffee();
}
if (!milk.isMilk())
milk.makeMilk();
}
}
abstract class CoffeeTemplate {
//咖啡名称
private String coffeeName;
//构造函数
public CoffeeTemplate(String coffeeName) {
this.coffeeName = coffeeName;
}
//定义制造咖啡的模板方法
final void makeCoffee() {
System.out.println("making " + coffeeName + ": ");
grindingCoffeeBeans();
brewingCoffee();
addingCondiments();
}
//定义制造牛奶的模板方法
final void makeMilk() {
System.out.println("making " + coffeeName + ": ");
addingCondiments();
}
//定义实现模板方法的基本方法
//研磨方法
void grindingCoffeeBeans() {
System.out.println("研磨咖啡豆");
}
//冲泡咖啡
void brewingCoffee() {
System.out.println("冲泡咖啡");
}
//添加调料根据咖啡的种类,调料不一样
//定义基本方法中的抽象方法
abstract void addingCondiments();
//定义钩子方法,判断是否是牛奶,牛奶不需要添加其他
boolean isMilk() {
return false;
}
}
//定义美式咖啡具体实现类
class American extends CoffeeTemplate {
public American() {
super("American Coffee");
}
@Override
void addingCondiments() {
System.out.println("添加American Coffee的调料");
}
}
//定义拿铁咖啡具体实现类
class Latte extends CoffeeTemplate {
public Latte() {
super("Latte Coffee");
}
@Override
void addingCondiments() {
System.out.println("添加Latte Coffee的调料");
}
}
//定义牛奶具体实现类,但是需要判断是否是牛奶
class Milk extends CoffeeTemplate {
public Milk() {
super("Milk");
}
@Override
void addingCondiments() {
System.out.println("牛奶不需要添加调料");
}
@Override
boolean isMilk() {
System.out.println("是牛奶,不需要添加调料");
return true;
}
}
7.2优点
- 当多个子类存在公共的行为时,可以将其提取出来并集中到一个公共父类中以避免代码重复。
- 当需要控制子类的扩展时,模板方法只在特定点调用钩子操作
8.Decorator 装饰器模式
8.1装饰器的实现思路
- 定义抽象构件,通过抽象接口规范准备接收附加责任的对象
- 定义具体构件,实现抽象构件,为装饰器添加一些职责
- 定义抽象装饰,继承抽象构件,并包含具体构件的实例,可以通过其子类扩展具体构件的功能
- 定义具体装饰,实现抽象装饰的相关方法,并给出具体构件对象添加附加的功能
小明喜欢品尝不同口味的咖啡,他发现每种咖啡都可以加入不同的调料,比如牛奶、糖和巧克力。他决定使用装饰者模式制作自己喜欢的咖啡。
请设计一个简单的咖啡制作系统,使用装饰者模式为咖啡添加不同的调料。系统支持两种咖啡类型:黑咖啡(Black Coffee)和拿铁(Latte)。
java
package com.technologystatck.designpattern.modereview.decorator;
public class Decorator {
public static void main(String[] args) {
CoffeeComponent latteCoffee = new LatteCoffee();
CoffeeComponent blackCoffee = new BlackCoffee();
latteCoffee.makeCoffee();
blackCoffee.makeCoffee();
System.out.println("====================");
new Milk(latteCoffee).makeCoffee();
new Sugar(blackCoffee).makeCoffee();
}
}
//定义抽象构件
abstract class CoffeeComponent{
//需要添加的调料名字
private String seasoning;
public CoffeeComponent() {
}
//可以自己手动传参
public CoffeeComponent(String seasoning) {
this.seasoning = seasoning;
}
public String getSeasoning() {
return seasoning;
}
public void setSeasoning(String seasoning) {
this.seasoning = seasoning;
}
//制作咖啡的方法
abstract void makeCoffee();
}
//定义具体构件
//黑咖啡的制作
class BlackCoffee extends CoffeeComponent{
public BlackCoffee() {
super("黑咖啡浓缩原液");
}
@Override
void makeCoffee() {
System.out.println("making "+super.getSeasoning()+" black coffee");
}
}
//拿铁的制作
class LatteCoffee extends CoffeeComponent{
public LatteCoffee() {
super("拿铁咖啡浓缩原液");
}
@Override
void makeCoffee() {
System.out.println("making "+super.getSeasoning()+" latte coffee");
}
}
//定义抽象装饰
abstract class CoffeeDecorator extends CoffeeComponent{
//实例化抽象构件
private CoffeeComponent coffeeComponent;
public CoffeeComponent getCoffeeComponent() {
return coffeeComponent;
}
public void setCoffeeComponent(CoffeeComponent coffeeComponent) {
this.coffeeComponent = coffeeComponent;
}
//默认构造方法
public CoffeeDecorator(String seasoning, CoffeeComponent coffeeComponent) {
super(seasoning);
this.coffeeComponent = coffeeComponent;
}
}
//定义具体装饰
//黑咖啡具体装饰类
class Milk extends CoffeeDecorator{
public Milk(CoffeeComponent coffeeComponent) {
//添加额外的操作
//添加半杯奶
super("半杯奶", coffeeComponent);
}
@Override
void makeCoffee() {
System.out.println("制作"+super.getSeasoning()+"的黑咖啡");
}
}
class Sugar extends CoffeeDecorator{
//添加额外的操作
//添加两勺糖
public Sugar( CoffeeComponent coffeeComponent) {
super("两勺糖", coffeeComponent);
}
@Override
void makeCoffee() {
System.out.println("添加了"+super.getSeasoning()+"的拿铁");
}
}
8.2优点
- 在不影响其他对象的情况下,动态的给单个对象添加职责。
- 声明目标对象时需要实现与目标类相同的业务接口
- 可以在不修改目标类的前提下增强目标方法
9.Observer 观察者模式
9.1观察者的实现思路
- 定义抽象主题,定义的接口中提供了一个用于保存观察者对象的聚集类和增加、删除观察者对象的方法,以及通知所有观察者对象的抽象方法
- 定义具体主题,用于实现抽象主题中的通知方法,当具体主题的内部状态发生改变时,通知所有注册过的观察者对象
- 定义抽象观察者,定义的接口中包含了更新自己的抽象方法,当接到具体主题的更改通知时被调用
- 定义具体观察者,实现抽象观察者中定义的抽象方法,当主题内部状态发生变化时,就通知到具体观察者并进行处理
小明所在的学校有一个时钟(主题),每到整点时,它就会通知所有的学生(观察者)当前的时间,请你使用观察者模式实现这个时钟通知系统。
注意点:时间从 0 开始,并每隔一个小时更新一次。
java
package com.technologystatck.designpattern.modereview.observer;
import java.util.ArrayList;
import java.util.List;
public class ClockObserver {
public static void main(String[] args) {
Clock clock = new Clock();
ConcreteObserver concreteObserver1 = new ConcreteObserver("张三");
ConcreteObserver concreteObserver2 = new ConcreteObserver("李四");
ConcreteObserver concreteObserver3 = new ConcreteObserver("王五");
//注册三个新用户
clock.register(concreteObserver1);
clock.register(concreteObserver2);
clock.register(concreteObserver3);
//通知方法通知所有的人
clock.notifys("正在注册新用户");
//提供注销用户
clock.removes(concreteObserver2);
//通知方法通知所有的人
clock.notifys("正在注销用户"+concreteObserver2.getName());
for(int i=0,updates=3;i<updates;i++){
clock.tick();
}
}
}
//定义抽象主题
interface Subject{
//增加订阅者
void register(Observer observer);
//删除订阅者
void removes(Observer observer);
//通知订阅者
void notifys(String messages);
}
//定义具体主题
class Clock implements Subject{
//存储所有的用户
private List<Observer> observers=new ArrayList<>();
private int hour=0;
@Override
public void register(Observer observer) {
observers.add(observer);
}
@Override
public void removes(Observer observer) {
observers.remove(observer);
}
@Override
public void notifys(String messages) {
for (Observer observer : observers) {
//调用更新方法通知全局
observer.update(messages);
}
}
//定义方法 模拟时钟
public void tick(){
hour=(hour+1)%24;
//通知时间
notifys("现在时间: "+hour);
}
}
//定义抽象观察者
interface Observer{
void update(String messages);
}
//定义具体观察者
class ConcreteObserver implements Observer{
private String name;
public ConcreteObserver(String name) {
this.name = name;
}
public String getName() {
return name;
}
@Override
public void update(String messages) {
System.out.println(this.name+" --> "+messages);
}
}
9.2优点
- 对象间存在一对多关系,一个对象的状态发生改变会影响其他对象
- 类似广播机制,不需要具体收听者,只需分发广播
10.Strategy 策略模式
10.1策略模式的实现思路
- 抽象策略类,定义一个公共接口,各种不同的算法以不同的方式实现接口,环境角色使用该接口调用不同的算法
- 具体策略类,实现抽象策略定义的接口,并提供具体的算法实现
- 环境类(上下文类),包含一个策略实例,并在需要时调用策略对象的方法
小明家的超市推出了不同的购物优惠策略,你可以根据自己的需求选择不同的优惠方式。其中,有两种主要的优惠策略:
- 九折优惠策略:原价的90%。
- 满减优惠策略:购物满一定金额时,可以享受相应的减免优惠。
具体的满减规则如下:
满100元减5元
满150元减15元
满200元减25元
满300元减40元
请你设计一个购物优惠系统,用户输入商品的原价和选择的优惠策略编号,系统输出计算后的价格。
java
package com.technologystatck.designpattern.modereview.strategy;
public class Strategy {
public static void main(String[] args) {
DiscountContext discountContext = new DiscountContext();
DiscountStrategy9 discountStrategy9 = new DiscountStrategy9();
DiscountStrategyFull discountStrategyFull = new DiscountStrategyFull();
// discountContext.setStrategy(discountStrategy9);
discountContext.setStrategy(discountStrategyFull);
int price = discountContext.applyDiscount(120);
System.out.println("折扣后的价格"+price);
}
}
//定义抽象策略类
interface DiscountStrategy {
//定义算法方法
int applyDiscount(int originalPrice);
}
//定义具体策略类
//定义九折优惠策略类
class DiscountStrategy9 implements DiscountStrategy {
@Override
public int applyDiscount(int originalPrice) {
return (int) (originalPrice * 0.9); //返回九折优惠后的价格(保留两位小数)
}
}
//定义满减优惠策略类
class DiscountStrategyFull implements DiscountStrategy {
//定义满足的价格
private int[] thresholds={100,150,200,300};
//定义满减的价格
private int[] discounts={5,15,25,40};
@Override
public int applyDiscount(int originalPrice) {
//先遍历满足的价格
for(int i=thresholds.length-1;i>=0;i--){
//若价格有大于或等于满足价格中
//从最高的价格开始遍历,若有,则返回满减价格
//例如,如果大于300,则因为从后开始遍历,所以满减的价格也是从后开始遍历,则是减去40
if(originalPrice>=thresholds[i]){
//返回满减价格
return originalPrice-discounts[i];
}
}
//若价格小于满足价格数组,则返回原价
return originalPrice;
}
}
//定义上下文类
class DiscountContext {
private DiscountStrategy strategy;
//设置方法
public void setStrategy(DiscountStrategy strategy) {
this.strategy = strategy;
}
//输入原价格
//通过该类来调用折扣方法,进行价格折扣
public int applyDiscount(int orignalPrice) {
return strategy.applyDiscount(orignalPrice);
}
}
10.2优点
- 一个系统需要动态地在几种算法中选择一种时,可将每个算法封装到策略类中
- 系统中各个算法独立,根据运行时动态选择具体要执行的行为