-
1、单例模式
-
核心作用
保证一个类只有一个实例,并且提供一个访问该实例的全局访问点
-
单例模式的应用场景
应用程序的日志,数据库连接池,Spring中bean默认单例,Spring MVC框架中,控制器对象也是 单例的,每个Servlet也是单例的
-
常见的五种单例模式的实现方式
- 懒汉式(线程安全,调用效率不高,但是可以延时加载)
- 饿懒汉式(线程安全,调用效率高,但是不能延时加载)
- 双重检测锁式(由于虚拟机内部优化的问题,可能会出问题, 但在J2SE5.0中已经被修复)
- 静态内部类式(线程安全,调用效率高,但是可以延时加载)
- 枚举单例(线程安全,调用效率高,不能延时加载)
-
Java具体实现
- 懒汉模式
import java.io.Serializable;
/**
* 懒汉式的单例模式
* 真正使用的时候才会加载
* 资源的利用率变高,但是每次调用 getInstance方法都需要同步
* 并发效率较低
*/
public class LazyStyle implements Serializable{
private static final long serialVersionUID = 1L;
private static int count = 0;
private static LazyStyle instance;
private LazyStyle() {
synchronized (LazyStyle.class) {
if (count >0) {
throw new RuntimeException("多实例异常");
}
count ++;
}
}
public static synchronized LazyStyle getInstance(){
if (instance ==null) { //如果实例不存在,则创建
instance = new LazyStyle();
}
return instance;
}
/** 防止反序列化漏洞 ,反序列化时直接调用该方法,而不需要生成新的对象*/
private Object readResolve() {
return instance;
}
}
/**
* 如何防止反射和反序列化漏洞[基于懒汉单例模式]
* 怎样解决该问题:在私有构造方法中,通过构造行数的调用次数来判断,大于0则抛出异常
* 反序列化漏洞可以通过定义readResolve方法解决
*
*/
public class ReflectionAndSerializableShortage {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException, IOException {
//reflect();
serializable();
}
@SuppressWarnings({ "unchecked" })
public static void reflect() throws ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException{
//通过反射的方式破坏单例
Class<LazyStyle> clazz = (Class<LazyStyle>)Class.forName("com.ethan.design.patterns.creater.singleton.LazyStyle");
Constructor<LazyStyle> constructor = clazz.getDeclaredConstructor();
constructor.setAccessible(true);
LazyStyle obj = constructor.newInstance();
LazyStyle obj1 = constructor.newInstance();
System.out.println("obj:" + obj);
System.out.println("obj1:" + obj1);
System.out.println("obj==obj1:"+(obj==obj1));
}
public static void serializable() throws IOException, ClassNotFoundException {
//通过反序列化构造多个对象
//可以通过readResolve方法解决
LazyStyle obj = LazyStyle.getInstance();
FileOutputStream fos = new FileOutputStream("f:/a.txt");
ObjectOutputStream oos = new ObjectOutputStream(fos);
oos.writeObject(oos);
oos.close();
fos.close();
FileInputStream fis = new FileInputStream("f:/a.txt");
@SuppressWarnings("resource")
ObjectInputStream ois = new ObjectInputStream(fis);
LazyStyle obj1 = (LazyStyle) ois.readObject();
System.out.println("obj==obj1:"+ (obj==obj1));
}
- 饿汉模式
package com.ethan.design.patterns.creater.singleton;
/**
* 饿汉式单例模式
* 饿汉模式中,static变量会在类装载时初始化,此时不会涉及多个线程对象
* 访问该对象的问题。虚拟机保证只会装载一次该类,肯定不会发生并发访问的
* 问题。因此可以省略synchronized关键字
* 问题:如果只是加载本类,而不是调用getInstance,甚至永远没有调用,则
* 会造成资源浪费。
*
* 饿汉模式的典型实例:Java中的Runtime类
*/
public class StarveStyle {
/** 类初始化时,立即加载 */
private static StarveStyle instance = new StarveStyle();
/* 私有构造器 */
private StarveStyle(){}
public static StarveStyle getInstance(){
return instance;
}
}
- 双重检测锁式
/**
* Double Check
*/
public class DoubleCheckLockStyle {
private volatile static DoubleCheckLockStyle instance = new DoubleCheckLockStyle();
private DoubleCheckLockStyle() {}
public static DoubleCheckLockStyle getInstance() {
if (instance == null) {
synchronized(DoubleCheckLockStyle.class) {
if (instance == null) {
instance = new DoubleCheckLockStyle();
}
}
}
return instance;
}
}
- 静态内部类式
/**
* 静态内部类的实现
* 外部类没有static属性,不会像饿汉式那样立即加载对象
* 只有真正调用getInstance,才会加载静态内部类,加载类时是线程安全的
* instance是static final 类型,保证内存中只有一个这样的实例存在,
* 而且只能被赋值一次,从而保证线程的安全性
* 兼备了高并发调用和延迟加载的优势
*/
public class InnerStaticClassStyle {
private static class InnerClass{
private static final InnerStaticClassStyle instance
= new InnerStaticClassStyle();
}
private InnerStaticClassStyle(){}
public static InnerStaticClassStyle getInstance() {
return InnerClass.instance;
}
}
- 枚举单例
/**
* 枚举实现单例模式
* 枚举本身就是单例模式,由JVM从根本上提供保障
* 避免通过反射和反序列化的漏洞
* 缺点:无延迟加载
*/
public enum EnumStyle {
//这个枚举元素,本身就是单例对象
INSTANCE;
public void operator() {
//具体的功能处理
}
/** 测试代码 */
public static void main(String[] args){
EnumStyle ins = EnumStyle.INSTANCE;
EnumStyle ins1 = EnumStyle.INSTANCE;
System.out.println(ins == ins1); //true
}
}
2、原型模式
/**
* 如果需要短时间创建大量对象
* 并且new的过程比较耗时,则可以
* 考虑原型模式
*/
public class CloneTest {
public static void main(String[] args) throws CloneNotSupportedException {
Sheep sheep = new Sheep("Duoli", new Date());
Sheep clone = (Sheep) sheep.clone();
System.out.println("original: " + sheep.toString()+ " clone: "+ clone.toString());
System.out.println("origin==new?: "+(sheep==clone));//FALSE
/** 如果为浅复制则为TRUE,如果为深复制,则为FALSE */
System.out.println("originDATE==newDATE?: "+(sheep.getBirthday()==clone.getBirthday()));
}
}
/**
* 如果要克隆的话,必须要实现Cloneable接口
* clone()方法存在于Object类中
*/
public class Sheep implements Cloneable{//1997英国的克隆羊,多利
private String name;
private Date birthday;
public Sheep(String name, Date birthday){
this.name = name;
this.birthday = birthday;
}
@Override
protected Object clone() throws CloneNotSupportedException {
Sheep sheep = (Sheep)super.clone();
//实现深克隆
sheep.setBirthday((Date)sheep.getBirthday().clone());
return sheep;
}
@Override
public String toString() {
return "Sheep [name=" + name + ", birthday=" + birthday + "]";
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirthday() {
return birthday;
}
public void setBirthday(Date birthday) {
this.birthday = birthday;
}
}
public class SimpleClonePojo implements Cloneable,Serializable{
private static final long serialVersionUID = 1L;
private String name;
private Date birth;
private int age;
public SimpleClonePojo() {
super();
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getBirth() {
return birth;
}
public void setBirth(Date birth) {
this.birth = birth;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public SimpleClonePojo(String name, Date birth, int age) {
super();
this.name = name;
this.birth = birth;
this.age = age;
}
@Override
public String toString() {
return "SimpleClonePojo [name=" + name + ", birth=" + birth + ", age=" + age + "]";
}
}
/**
* 通过序列化和反序列化实现深克隆
*/
public class DeepCloneBySerializable {
public static void main(String[] args) {
new DeepCloneBySerializable().deep();
}
/**
* 通过序列化和反序列化实现深克隆
*/
public void deep() {
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ByteArrayInputStream bai = null;
ObjectOutputStream oos = null;
ObjectInputStream ois = null;
SimpleClonePojo pojo = new SimpleClonePojo("反序列化对象克隆",new Date(232332L), 20);
try {
oos = new ObjectOutputStream(bos);
/**序列化,将对象写入到字节数组流中*/
oos.writeObject(pojo);
byte[] arr = bos.toByteArray();
bai = new ByteArrayInputStream(arr, 0, arr.length);
ois = new ObjectInputStream(bai);
/** 反序列化读取对象 */
SimpleClonePojo cp = (SimpleClonePojo) ois.readObject();
System.out.println("pojo==cp:? "+ (pojo == cp)); //FALSE
System.out.println("pojo.birth==cp.birth:? "+
(pojo.getBirth() == cp.getBirth())); //FALSE
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
3、工厂模式
- 简单工厂
package com.ethan.design.patterns.creater.factory;
import com.ethan.design.patterns.pojo.Audi;
import com.ethan.design.patterns.pojo.Bench;
import com.ethan.design.patterns.pojo.Car;
/**
* 简单工厂模式
* 工厂模式实现了创建者和调用者的分离
* 简单工厂的问题:无法保证在添加新的内容时,不修改原来的代码
* 如:要添加其他车时,需要修改getCar方法中的代码,违反了开闭原则
*/
public class SimpleFactory {
public static Car getCar(String type) {
if ("audi".equals(type)) {
return new Audi();
}else if ("bench".equals(type)) {
return new Bench();
}else {
throw new RuntimeException("无相关车辆");
}
}
}
- 工厂方法
package com.ethan.design.patterns.creater.factory;
import com.ethan.design.patterns.pojo.Car;
/**
* 工厂方法模式
* 创建接口,由具体的工厂实现该接口
* 工厂方法模式,从复杂度上来说比简单工厂模式要复杂
* 但是其满足开闭原则,对扩展开放
*/
public interface FactoryMethod {
Car createCar();
}
public class AudiFactory implements FactoryMethod{
public Car createCar() {
return new Audi();
}
}
public class BenchFactory implements FactoryMethod{
public Car createCar() {
return new Bench();
}
}
- 抽象工厂
package com.ethan.design.patterns.creater.abstractfactory;
/**
* 抽象工厂模式
* 对于单一产品增加的无能为力,可以由简单工厂和工厂方法解决
* 抽象工厂模式可以看做是产品族的生产,如发动机,座椅,轮胎
* 高端发动机,高端座椅,高端轮胎是一个产品族
* 中端发动机,中端座椅,中端轮胎是一个产品族
* 低端发动机,低端座椅,低端轮胎是一个产品族
*
* 举例说明:其中抽象工厂AbstractFacroty有三个方法:
* 1、createEngine()
* 2、createTyre()
* 3、createSeat()
* HighFacroty 高端工厂
* MediumFacroty 中端工厂
* LowFactory低端工厂
* 均实现AbstractFacroty接口
*
* Engine 又有不同的实现类: LowEngine、MidiumEngine、HighEngine
* Tyre 又有不同的实现类: LowTyre、MidiumTyre、HighTyre
* Seat 又有不同的实现类: LowSeat、MidiumSeat、HighSeat
*
*/
public interface AbstractFactory {
Engine createEngine();
Tyre createTyre();
Seat createSeat();
}
public class HighFactory implements AbstractFactory{
public Engine createEngine() {
return new HighEngine();
}
public Tyre createTyre() {
return new HighTyre();
}
public Seat createSeat() {
return new HighSeat();
}
}
public class HighEngine implements Engine{
public void start() {
System.out.println("高级发动机!");
}
}
public class HighTyre implements Tyre{
public void rotate() {
System.out.println("高级轮胎!");
}
}
public class HighSeat implements Seat{
public void support() {
System.out.println("高级座椅!");
}
}
/**
* 发动机类
*/
public interface Engine {
void start();
}
/**
* 轮胎类
*/
public interface Tyre {
void rotate();
}
/**
* 座椅类
*/
public interface Seat {
void support();
}
//测试
public class AbstractFacTest {
public static void main(String[] args) {
AbstractFactory factory = new HighFactory();
Engine engine = factory.createEngine();
Tyre tyre = factory.createTyre();
Seat seat = factory.createSeat();
engine.start();
tyre.rotate();
seat.support();
}
}
- 创建型模式
创建型模式:关注对象的创建过程
/** 飞行器组装 */
public interface DirectShip {
/**
* 组装飞船对象
* @Param builder 构建类
*/
AirShip directShip();
}
/** 不同组件的构建 */
public interface AirShipBuilder {
Engine buildEngine();//构建发动机
OrbitalModule buildOrbitalModule();//构建轨道舱
EscapeTower buildEscapeTower();//构建逃逸塔
}
/**
* 以后学习XML解析中,JDOM库中的类,DomBuilder,SaxBuilder
*/
public class MyAirShipBuilder implements AirShipBuilder{
public Engine buildEngine() {
//也可以使用工厂模式来创建,如发动机的工厂,通过工厂获取
return new Engine("我的发动机");
}
public OrbitalModule buildOrbitalModule() {
return new OrbitalModule("我的轨道舱");
}
public EscapeTower buildEscapeTower() {
return new EscapeTower("我的逃逸塔");
}
}
public class MyDirectShip implements DirectShip{
private AirShipBuilder builder;
public MyDirectShip(AirShipBuilder builder) {
this.builder = builder;
}
public AirShip directShip() {
Engine en = builder.buildEngine();
OrbitalModule om = builder.buildOrbitalModule();
EscapeTower et = builder.buildEscapeTower();
AirShip ship = new AirShip();
ship.setEngine(en);
ship.setOrbitalModule(om);
ship.setEscapeTower(et);
return ship;
}
public AirShipBuilder getBuilder() {
return builder;
}
public void setBuilder(AirShipBuilder builder) {
this.builder = builder;
}
}
/**
* 飞船发动机
*/
public class Engine {
private String name;
public Engine(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "Engine [name=" + name + "]";
}
}
/**
* 轨道舱
*/
public class OrbitalModule {
private String name;
public OrbitalModule(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "OrbitalModule [name=" + name + "]";
}
}
/**
* 逃逸塔
*/
public class EscapeTower {
private String name;
public EscapeTower(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "EscapeTower [name=" + name + "]";
}
}
个人理解: 创建型模式围绕组装展开,关注组装的过程,被组装的产品通过接口被定义, 通过具体的Builder来实现, 具体组装的过程则由组装的接口来完成,也即可以实现既可以组装A类产品(产品包含不同的组件) 也可以组装B类产品,而A,B 类产品又达到了分离的目的,如果这时又C类产品通过实现Builder即可完成,达到对拓展开放,被修改关闭的原则
4、行为型模式
- 关注系统中对象之间的相互交互
- 研究系统在运行时对象之间的相互通信和协作
- 进一步明确对象的职责
包括11种模式:
- 责任链模式
- 命令模式
- 解释器模式:基本用不着,开发新的语言,可以考虑使用解释器模式,可用java的js等引 擎替换解释器的作用
- 迭代器模式
- 中介者模式
- 备忘录模式
- 观察者模式
- 状态模式
- 策略模式
- 模板方法模式
- 访问者模式
- 责任链模式
/**
* 责任链模式
*
* 定义:能够处理同一类请求的对象连城一条链,所提交的请求
* 沿着链传递,链上的对象逐个判断是否有能力处理该请求
* 如果能则处理,如果不能则传递给链上的下一个对象
*
* 场景:打牌时,轮流出牌
* 接力赛跑
* 奖学金审批
* 公文审批
*
* 典型:Java的try,catch
*
*/
public class ChainOfResponsibility {
public static void main(String[] args) {
new ChainOfResponsibility().test();
}
void test() {
LeaveRequest request1 = new LeaveRequest("a45689", 5, "事假1");
LeaveRequest request2 = new LeaveRequest("a45689", 15, "事假2");
Leader manager = new Manager("总经理");
Leader vice = new ViceManager("副总");
vice.setNextLeader(manager);
vice.handleRequest(request1);//我是副总经理,天数小于10,我可以处理
vice.handleRequest(request2);//我是总经理,天数大于10,我来处理
}
}
/** 抽象类,领导*/
abstract class Leader {
private String name;
/**下一位处理者*/
private Leader nextLeader;
public Leader(String name) {
super();
this.name = name;
this.nextLeader = null;
}
public Leader(String name, Leader nextLeader) {
super();
this.name = name;
this.nextLeader = nextLeader;
}
/** 核心处理方法 - 抽象,由具体的领导如:主任,经理,副总经理来实现 */
abstract void handleRequest(LeaveRequest request);
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Leader getNextLeader() {
return nextLeader;
}
public void setNextLeader(Leader nextLeader) {
this.nextLeader = nextLeader;
}
}
/**副总经理*/
class ViceManager extends Leader{
public ViceManager(String name) {
super(name, null);
}
public ViceManager(String name, Leader nextLeader) {
super(name, nextLeader);
}
@Override
void handleRequest(LeaveRequest request) {
if (request.getDays() < 10) {
Pr.pr("我是副总经理,天数小于10,我可以处理");
} else {
getNextLeader().handleRequest(request);
}
}
}
/** 总经理 */
class Manager extends Leader{
public Manager(String name) {
super(name, null);
}
public Manager(String name, Leader nextLeader) {
super(name, nextLeader);
}
@Override
void handleRequest(LeaveRequest request) {
if (request.getDays() >10) {
Pr.pr("我是总经理,天数大于10,我来处理");
}
}
}
/** 模拟请假的审批 */
class LeaveRequest {
/** 雇员名称或者编号 */
private String employee;
/** 请假天数 */
private int days;
/** 请假理由 */
private String desc;
public LeaveRequest(String employee, int days, String desc) {
super();
this.employee = employee;
this.days = days;
this.desc = desc;
}
public String getEmployee() {
return employee;
}
public void setEmployee(String employee) {
this.employee = employee;
}
public int getDays() {
return days;
}
public void setDays(int days) {
this.days = days;
}
public String getDesc() {
return desc;
}
public void setDesc(String desc) {
this.desc = desc;
}
@Override
public String toString() {
return "LeaveRequest [employee=" + employee + ", days=" + days + ", desc=" + desc + "]";
}
}
- 命令模式
/**
* 命令模式
*
* 调用者 -> 命令【命令实现类】 -> 接收者
* Invoke -> Command[ConcreteCommand] -> Receiver
*
* 设计模式的初中就是适应变化,便于扩展
*
* 场景:数据库底层的事务机制
*
*/
public class CommandClient {
public static void main(String[] args) {
new CommandClient().client();
}
void client(){
Receiver r = new Receiver();
Command command = new ConcreteCommand(r);
command.execute();
}
}
class Invoke {
//可以定义成List<Command>供批处理
private Command command;
public Invoke(Command command) {
super();
this.command = command;
}
public void invoke() {
command.execute();
}
}
class ConcreteCommand implements Command{
private Receiver receiver;
public ConcreteCommand(Receiver receiver) {
super();
this.receiver = receiver;
}
public void execute() {
receiver.action();
}
}
interface Command{
void execute();
}
class Receiver {
public void action() {
Pr.pr("执行前");
Pr.pr("action");
Pr.pr("执行后");
}
}
- 迭代器模式
/**
* 迭代器模式
*
*/
public class IteratorClient {
public static void main(String[] args) {
new IteratorClient().test();
}
void test(){
List<Object> eles = new ArrayList<Object>();
eles.add("121");eles.add("yifus");eles.add("b23d");
Container c = new Container(eles);
Iterat i = c.getIterator();
while(i.hasNext()) {
Object o = i.getCurrentObj();
i.next();
Pr.pr(o.toString());
}
}
}
/** 迭代器接口 */
interface Iterat {
void first(); //将游标指向第一个元素
void next(); //将游标指向下一个元素
Object getCurrentObj();//获取当前游标指向的对象
boolean hasNext();
boolean isFirst();
boolean isLast();
}
/** 聚合类,也可以称之为容器类 */
class Container {
private List<Object> list = new ArrayList<Object>();//简单实现
public Container() {
super();
}
public Container(List<Object> list) {
super();
this.list = list;
}
/**获取迭代器*/
public InnerItera getIterator() {
return new InnerItera();
}
public void addObject(Object obj) {
list.add(obj);
}
public void removeObject(Object obj) {
list.remove(obj);
}
/**
* 用内部类实现迭代器
*/
private class InnerItera implements Iterat{
private int cursor;
public void first() {
cursor = 0;
}
public void next() {
if (cursor < list.size()) {
cursor++;
}
}
public boolean hasNext() {
if (cursor < list.size()) {
return true;
}
return false;
}
public boolean isFirst() {
return cursor == 0;
}
public boolean isLast() {
return cursor==(list.size()-1);
}
public Object getCurrentObj() {
return list.get(cursor);
}
}
}
- 中介者模式
/**
* 中介者模式
*
* 财务部,市场部,研发部分别跟总经理打交道,而不是各自为政
*
* 核心:把网状结构重新解耦,变成一对多
* 同事对象 - 中介者对象
*
* 核心: Mediator中介者,Department部门抽象,各个部分实现Market,Development,Financial
* 需要在各自持有的Mediator中注册,由具体实现的Mediator统一发布指令或者任务
*
* 场景:MVC模式中的C
* 控制器就是一个中介者对象,M和V都和它打交道
*
*/
public class MediatorClient {
public static void main(String[] args) {
new MediatorClient().client();
}
@SuppressWarnings("unused")
void client(){
Mediator m = new ReputationManager();
Department market = new Market(m);
Department develope = new Development(m);
Department financial = new Financial(m);
m.command("market", "找客户推荐新产品");
m.command("financial", "给研发部一笔新的启动金");
m.command("development", "研发新产品");
}
}
/** 中介者 - 其他部分有事需要向其反馈,再由它分发任务 */
interface Mediator {
void register(String dname, Department department);
void command(String dname, String command);
}
/** 部门 */
interface Department {
void selfAction();//部门内的事情
void selfAction(String command);//部门内的事情
void outAction();//向总经理发出申请
}
//研发部
class Development implements Department {
private Mediator m;
public Development(Mediator m) {
super();
this.m = m;
m.register("development", this);
}
public void setM(Mediator m) {
this.m = m;
m.register("development", this);
}
public Mediator getM() {
return m;
}
public void selfAction() {
Pr.pr("开发项目");
}
public void outAction() {
Pr.pr("没钱了,需要资金支持");
}
public void selfAction(String command) {
Pr.pr("研发部接到指令:"+command);
selfAction();
Pr.pr("==============分隔线======================");
}
}
//财务部
class Financial implements Department{
private Mediator m;
public Financial(Mediator m) {
super();
this.m = m;
m.register("financial", this);
}
public Mediator getM() {
return m;
}
public void setM(Mediator m) {
this.m = m;
m.register("financial", this);
}
public void selfAction() {
Pr.pr("财务管理");
}
public void outAction() {
Pr.pr("汇报工作,钱怎么花");
}
public void selfAction(String command) {
Pr.pr("财务部接到指令");
selfAction();
Pr.pr("==============分隔线======================");
}
}
//市场部
class Market implements Department {
private Mediator m;
public Market(Mediator m) {
this.m = m;
m.register("market", this);
}
public Mediator getM() {
return m;
}
public void setM(Mediator m) {
this.m = m;
m.register("market", this);
}
public void selfAction() {
Pr.pr("市场拓展");
}
public void outAction() {
Pr.pr("汇报市场工作");
}
public void selfAction(String command) {
Pr.pr("市场部接到指令:"+command);
selfAction();
Pr.pr("==============分隔线======================");
}
}
/** 总经理 */
class ReputationManager implements Mediator{
private Map<String,Department> dept = new HashMap<String,Department>();
public void register(String dname, Department department) {
dept.put(dname,department);
}
public void command(String dname, String command) {
Department d = dept.get(dname);
if (d!=null) {
d.selfAction(command);
}
}
}
- 备忘录模式
/**
* 备忘录模式
*
* 回复到之前的状态
*
* 开发场景:悔棋,撤销操作
* 数据库软件中,事务管理中的回滚操作
* 历史记录
*/
public class MementoClient {
private EmpMemento emo;//或者使用List,保存多个状态
public EmpMemento getEmo() {
return emo;
}
public MementoClient(EmpMemento emo) {
super();
this.emo = emo;
}
public static void main(String[] args) {
Emp emp = new Emp(20,"马丽");
Pr.pr(emp.toString());//Emp [age=20, name=马丽]
EmpMemento emo = emp.bak();
MementoClient c = new MementoClient(emo);
emp.setAge(30);
Pr.pr(emp.toString());//Emp [age=30, name=马丽]
emp.recover(c.getEmo());
Pr.pr(emp.toString());//Emp [age=20, name=马丽]
}
}
class EmpMemento {
private int age;
private String name;
public EmpMemento(Emp emp) {
this.age = emp.getAge();
this.name = emp.getName();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
}
class Emp {
private int age;
private String name;
public int getAge() {
return age;
}
/** 恢复 */
public void recover(EmpMemento empm) {
this.age = empm.getAge();
this.name = empm.getName();
}
/** 备忘 */
public EmpMemento bak() {
return new EmpMemento(this);
}
public void setAge(int age) {
this.age = age;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Emp(int age, String name) {
super();
this.age = age;
this.name = name;
}
@Override
public String toString() {
return "Emp [age=" + age + ", name=" + name + "]";
}
}
- 观察者模式
/**
* 观察者模式
* 广播-群发消息
*
* java.util.Observable和java.util.Observer实现了该模式
* 两者分别为类和接口
*
* 场景:监听器的实现
* Android中,广播机制
* AWT:事件源--目标对象;时间监听器--观察者
*/
public class ObserverClient {
public static void main(String[] args) {
new ObserverClient().test();
}
void test(){
Observer o1 = new SomeObserver("观察者1");
Observer o2 = new SomeObserver("观察者2");
Observer o3 = new SomeObserver("观察者3");
Observable sender = new SomeSender();
sender.add(o1);
sender.add(o2);
sender.add(o3);
sender.send("我发了一个消息给你们hah!");
Pr.pr("=========================================");
sender.remove(o3);
sender.send("我们团队成员少了一个!");
}
}
/** 消息发送者 */
interface Observable {
void send(String msg);
void add(Observer ob);
void remove(Observer ob);
}
/** 消息发送者的实现类 */
class SomeSender implements Observable {
private List<Observer> obs = new ArrayList<Observer>();
/** 注册 */
public void add(Observer ob){
obs.add(ob);
}
/**移除*/
public void remove(Observer ob) {
obs.remove(ob);
}
/** 发送消息 */
public void send(String msg) {//遍历,向注册的观察者发消息
ListIterator<Observer> i = obs.listIterator();
while(i.hasNext()) {
i.next().read(msg);
}
}
}
/** 观察者 */
interface Observer{
void read(String msg);//读取消息
}
/** 观察者实现类 */
class SomeObserver implements Observer{
private String name;
public SomeObserver(String name) {
super();
this.name = name;
}
public String getName() {
return name;
}
public void read(String msg) {
Pr.pr("我是:"+name+",我接受到的消息是:"+msg);
}
}
- 状态模式
/**
* 状态模式
*
* 常见使用场景:红绿灯:红灯、路灯、黄灯
* 订单状态:下单、已付款、已发货、送货中、已收货
* 电梯的运行:向上、向下、开门、关门、维修
*
*/
public class StateClient {
public static void main(String[] args) {
new StateClient().test();
}
void test(){
State state = new OrderedState();
RoomContext c = new RoomContext(state);
c.show();//酒店房间处于预订状态
//切换状态
state = new FreeState();
c.setState(state);
c.show();//酒店房间处于空闲状态
}
}
/** 状态的抽象类 */
interface State {
void handle();
}
/** 不同的子类状态来实现State*/
class OrderedState implements State{
public void handle() {
Pr.pr("酒店房间处于预订状态");
}
}
class FreeState implements State{
public void handle() {
Pr.pr("酒店房间处于空闲状态");
}
}
class ReturnState implements State{
public void handle() {
Pr.pr("酒店房间处于退订状态");
}
}
class RoomContext {
private State state;
public RoomContext(State state) {
super();
this.state = state;
}
public State getState() {
return state;
}
public void setState(State state) {
this.state = state;
}
public void show() {
state.handle();
}
}
- 策略模式
/**
* 策略模式
*
* 策略模式对应于解决某一个问题的算法族,允许用户从该算法族
* 中任选一个算法解决某一问题,同时可以方便的更换算法或者增加
* 新的算法,并且由客户端决定调用哪个算法
*
* 场景 Spring框架中,Resource接口,资源访问策略
* HttpServlet.service()子Service
*/
public class StrategyClient {
public static void main(String[] args) {
new StrategyClient().test();
}
void test(){
Strategy s = new One();
Strategy s1 = new Two();
Context c = new Context(s);
Pr.pr("策略1价格:"+c.invoke(10023.5));
c.setStra(s1);
Pr.pr("策略2价格:"+c.invoke(10023.5));
//策略1价格:10023.5
//策略2价格:9021.15
}
}
class Context{
//注入具体的策略
private Strategy stra;
public Context(Strategy stra) {
super();
this.stra = stra;
}
public void setStra(Strategy stra) {
this.stra = stra;
}
public double invoke(double price) {
return stra.getPrice(price);
}
}
interface Strategy{
double getPrice(double originPrice);
}
/**普通客户小批量购买*/
class One implements Strategy{
public double getPrice(double originPrice) {
return originPrice;
}
}
/**普通客户大批量 */
class Two implements Strategy{
public double getPrice(double originPrice) {
return originPrice*0.9;
}
}
/** 老客户小批量 */
class Three implements Strategy{
public double getPrice(double originPrice) {
return originPrice*0.85;
}
}
/** 老客户大批量 */
class Four implements Strategy{
public double getPrice(double originPrice) {
return originPrice*0.8;
}
}
- 模板方法模式
/**
* 模板方法模式
*
* 场景:客户到银行办理业务-取号排队-办业务-给银行工作人员评分
* 请客-点单-吃东西-买单
*
* 作用:定义一个操作中的算法挂架,将某些步骤延迟到子类中实现
* 新的子类可以再不改变一个算法结构的前提下重新定义该算法的某些
* 特定步骤
* 使用场景:实现一个算法时,整体步骤很固定,但是在某些部分易变
* 易变部分可以抽象出来,供子类实现
* 开发场景:数据库访问的封装,Junit单元测试
* Servlet中关于doGet/doPost方法调用
* Spring中JDBCTemplate,HibernateTemplate
*/
public class TemplateMethodClient {
public static void main(String[] args) {
new TemplateMethodClient().test();
}
void test(){
BankService service = new SomeBank();
service.process();
}
}
/** 银行服务,定义模板方法的抽象类 */
abstract class BankService {
void getNum(){//模板方法简单实现
Pr.pr("得到号码");
}
abstract void transact();//办业务,钩子方法,待子类实现
void evaluate() {
Pr.pr("客户打分");
}
//定义成final,确保调用的顺序
public final void process() {
getNum();
transact();
evaluate();
}
}
/** 具体要办理的银行业务,继承BankService,并实现抽象方法transact **/
class SomeBank extends BankService {
@Override
void transact() {
Pr.pr("=============================");
Pr.pr("出示证件");
Pr.pr("我要取款");
Pr.pr("=============================");
}
}
5、结构型模式
关注对象和类的组织包括:
- 代理模式 :为真实对象提供一个代理,从而控制对真实对象的访问
- 适配模式: 使原本由于接口不兼容不能一起工作的类,可以一起工作
- 桥接模式:处理多层继承结构,处理多维度变化的场景,使各个维度设计成独立地继承结构,使各个维度可以独立地扩展在抽象层建立关联
- 组合模式:将对象组合成树状结构以表示“部分和整体”层次结构使得客户可以统一的调用叶子对象和容器对象
- 装饰模式:动态地给一个对象添加额外的功能,比继承灵活
- 外观模式:外子系统提供统一的调用接口,使得子系统更加容易使用
- 享元模式:运用共享技术有效地实现管理大量细粒度对象,节省内存,提高效率
- 适配器模式
1、适配器
举例:
三孔插头转换头 | 两孔插头
-- _
|_ ---
-- _ |------
|_ ---
--
/**
* 适配器模式
* 实例:【国外的三孔插座】和【两孔转三孔的转换头】
* 模式中的角色:
* 目标接口(Targer):客户所期待的接口,目标可以是具体的或抽象的类,也可以是接口
* 需要适配的类(Adaptee):需要适配的类或适配者类,如:三孔插座
* 适配器(Adapter):通过包装一个需要适配的对象,把原接口转换成目标接口
*
* 常见的场景
* InputStreamReader(InputStream)
* OutputStreamWriter(OutputStream)
*
*/
public class AdapteeAnAdapterClient {
public static void main(String[] args) {
AdapteeAnAdapterClient client = new AdapteeAnAdapterClient();
Adaptee adaptee = new Adaptee();//被适配的类
Target target = new Adapter(adaptee);//目标接口
client.adapt(target);
}
public void adapt(Target target) {
target.twoHoles();
}
}
/**
* 目标接口
*/
interface Target{
void twoHoles();
}
/**
* 需要被适配的对象
*/
class Adaptee{
public void threeHoles() {
System.out.println("三孔插座在工作");
}
}
/**
* 适配器
*/
class Adapter implements Target {
private Adaptee adaptee;
public Adapter(Adaptee adaptee) {
super();
this.adaptee = adaptee;
}
public void twoHoles() {
System.out.println("两孔操作在工作");
adaptee.threeHoles();
}
}
- 桥接模式
/**
*桥接模式
* 处理问题:
*
* 联想台式机
* 台式机 戴尔台式机
* 神舟台式机
*
* 联想笔记本
* 电脑 --- 笔记本 戴尔笔记本
* 神舟笔记本
*
* 联想平板电脑
* 平板电脑 戴尔平板电脑
* 神舟平板电脑
*
* 如果实现上述的继承体系,不仅复杂,面临类的个数的巨大膨胀,而且冗余繁琐
*
* 解决方式:将品牌和类型分开如:【联想】【平板】分开形成两个维度
* 类型
* |
* 台式机 |
* 笔记本 | (桥接)
* 平板电脑 |
* — - - - - - - - - - - 品牌
* 联想 戴尔 神舟
*
* 电脑类中持有Brand,新添加品牌或者类型都会更容易,取代多重继承结构
*/
public class BridgeClient {
public static void main(String[] args) {
Brand brand = new Lenovo() ;
Computer computer = new DeskTop(brand);
computer.sale();//联想品牌,销售台式机
}
void bridge(){
}
}
/** 电脑类 **/
class Computer{
private Brand brand;
public Computer(Brand brand){
this.brand = brand;
}
public void sale() {
this.brand.sale();
}
}
/** 台式机 */
class DeskTop extends Computer{
public DeskTop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
Pr.pr("销售台式机");
}
}
/** 笔记本 */
class LapTop extends Computer{
public LapTop(Brand brand) {
super(brand);
}
@Override
public void sale() {
super.sale();
Pr.pr("销售笔记本");
}
}
/** 品牌 */
interface Brand {
void sale();
}
class Lenovo implements Brand{
public void sale(){
Pr.pr("联想品牌");
}
}
class Dell implements Brand {
public void sale() {
Pr.pr("戴尔品牌");
}
}
- 组合模式
/**
*
* 组合模式
*
* 把部分和整体的干洗用树形结构表示,从而使客户端可以使用同一的方式处理
* 部分对象和整体对象
*
* 组合模式核心:
* 抽象构件(Component)角色:定义【叶子】和【容器】构件的共同点 - AbstractFile
* 叶子构件(Leaf)角色:无子节点 - ImageFile,TextFile
* 容器构件(Composite)角色:有容器特征,可以包含子节点 - Folder
*
* 场景:XML文件解析,OA系统中,组织结构处理
* Junit单元测试框架:TestCase(叶子)、TestUnite(容器)、Test接口
*/
public class CombineClient {
public static void main(String[] args) {
new CombineClient().test();
}
void test() {
AbstractFile img1,text1,img2,text2;
Folder f1,f2;
img1 = new ImageFile("图像1.jpg");
img2 = new ImageFile("图像2.jpg");
text1 = new TextFile("文本1.txt");
text2 = new TextFile("文本2.txt");
f1 = new Folder("文件夹1");
f2 = new Folder("文件夹2");
f2.add(text2);
f2.add(img2);
f1.add(img1);
f1.add(text1);
f1.add(f2);
f1.killVirus();
}
}
/** 抽象组件 - 抽象构件 - 文件 */
interface AbstractFile{
void killVirus();//杀毒过程
}
/** 叶子 - 图像文件的查杀 */
class ImageFile implements AbstractFile{
private String name;
public ImageFile(String name) {
this.name = name;
}
public void killVirus() {
Pr.pr("--图像文件:"+name+" 查杀过程");
}
}
/** 叶子 - 文本文件的查杀 */
class TextFile implements AbstractFile{
private String name;
public TextFile(String name) {
this.name = name;
}
public void killVirus() {
Pr.pr("--文本文件:"+name+" 查杀过程");
}
}
/** 文件夹 - 容器构件 */
class Folder implements AbstractFile{
private String name;
public Folder(String name) {
super();
this.name = name;
}
//存储子节点
private List<AbstractFile> value = new ArrayList<AbstractFile>();
public void killVirus() {
Pr.pr("--文件夹:"+name+" 查杀过程");
Iterator<AbstractFile> i = value.listIterator();
/** 通过递归实现,如果是文件,则直接查杀;如果是子文件夹,则递归 */
while(i.hasNext()) {
i.next().killVirus();
}
}
public void add(AbstractFile file) {
value.add(file);
}
public void remove(AbstractFile file){
value.remove(file);
}
public AbstractFile getChild(int index) {
return value.get(index);
}
}
- 装饰模式
/**
* 装饰模式
* 动态的为对象添加新的功能
*
* 是一种用于代替继承的技术,无须通过继承增加子类就能扩展对象的
* 新功能,使用对象的关联关系代替继承关系,更加灵活。
* 同时避免类型体系的快速膨胀
*
* 如:汽车,水上汽车,飞行汽车,人工智能汽车
*
* 实现细节:
* Component:抽象构件角色
* 真是对象和装饰对象有相同的接口,这样,客户端对象就能够以与真实对象相同的方式
* 同装饰对象交互
* ConcreteComponent 具体构件角色(真是对象):
* io流中的FileInputStream,FileOutputStream
* Decorator 装饰角色:
* 持有一个抽象构件的引用,装饰对象接口所有客户端的请求,并把这些请求转发给真实 的对象
* 这样就能在真实对象调用前后增加新的功能
*
* ConcreteDecorator具体装饰角色:
* 负责给构件对象增加新的责任
*
* 因为从上到下都是ICar接口进行处理,所以构造方法都是ICar,name可以不断增加新的功能
*
* Reader reader =
* new BufferedReader(InputStreamReader(new FileInputStream(new File())));
*
* Component:InputStream,OutputStream,Reader,Writer
* ConcreteComponent: FileInputStream,FileOutputStream
* Decorator: FilterInputStream,FilterOutputStream
* ConcreteDecorator:BufferedInputStream,BufferedOutputStream
*/
public class DecoratorClient {
public static void main(String[] args) {
new DecoratorClient().test();
}
void test(){
Car car = new Car();
ICar flyCar = new FlyCar(car);
flyCar.move();
}
}
/** 抽象组件 */
interface ICar{
void move();
}
class Car implements ICar{
public void move() {
Pr.pr("陆地上行驶");
}
}
/** 装饰器 */
class SuperCar implements ICar{
//持有真实对象的引用
protected ICar car;
public SuperCar(ICar car) {
super();
this.car = car;
}
public void move() {
car.move();
}
}
interface Flyable {
void fly();
}
/** 真实装饰器 */
class FlyCar extends SuperCar implements Flyable{
public FlyCar(ICar car) {
super(car);
}
public void fly() {
Pr.pr("天上飞");;
}
@Override
public void move() {
super.move();
fly();
}
}
- 动态代理
/**
* 动态代理
* 实现方式:JDK自带的动态代理java.lang.reflect.Proxy
* javassist字节码操作库实现
* CGLIB
* ASM(底层使用指令,可维护性较差)
*
* java.lang.reflect.InvocationHandler处理器接口
* 可以通过调用invoke方法实现对真实角色的代理访问;
* 每次通过Proxy生成代理类对象时都要指定对应的处理器对象
*
* AOP:Aspect Oriented Programming
* 可以通过预编译方式和运行期动态代理实现在不修改源代码的情况下给程序动态统一添加
* 功能的一种技术,它是一种新的方法论,是对传统的OOP编程的一种补充
*
* 切点形成切面,加入统一逻辑处理
*/
public class DynamicProxyClient {
public static void main(String[] args) {
new DynamicProxyClient().client();
}
void client() {
Action singer = new Singer();
SingerHandler handler = new SingerHandler(singer);
/**ClassLoader;真实类实现的接口;Handler(原来静态代理类做的事情,他来做)*/
Action proxy = (Action)Proxy.newProxyInstance(
ClassLoader.getSystemClassLoader(),
new Class[]{Action.class}, handler);
//相当于Proxy持有Handler,并通过invoke方法实现
proxy.contract();
proxy.sing();
proxy.getMoney();
}
}
class SingerHandler implements InvocationHandler {
Action object; //真实角色
public SingerHandler(Action object) {
super();
this.object = object;
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
/** com.ethan.design.structure.$Proxy0 */
//Pr.pr(proxy.getClass().getName());
if (method.getName().equals("sing")) {
/** 这里需要注意,调用方法invoke,传递的对象【object】是真实的对象不是【proxy】 */
method.invoke(object, args);
} else {
Pr.pr(method.getName()+" - 这是代理需要做的事情");
}
return null;
}
}
- 外观模式
/**
* 外观模式
* 迪米特法则:一个软件实体应当尽可能少的与其他实体发生相互作用
*
* 为子系统提供统一的入口,封装子系统的复杂性,便于客户端操作
* 注册公司:工商局 - 质检局 - 税务局 - 银行账户
* 相当于找了一个代理
*/
public class FacadeClient {
public static void main(String[] args) {
String material = "开公司需要的材料";
new FacadeClient().client(material);
}
void client(String material) {//客户只需要准备材料,知道找谁办理即可
new Registry(material).register();
}
}
class Registry {
private String material;
public Registry(String material) {
super();
this.material = material;
}
/**
* 统一的入口
*/
void register(){
Pr.pr("办理公司需要:" + material);
Pr.pr("Do A lot of things to found a company!");
}
}
- 享元模式
/**
* 享元模式
*
* 核心:享元模式以共享的方式高效地支持大量细粒度的对象重用
* 享元对象能做到共享的关键是区分了内部状态和外部状态
* 内部状态:可以共享,不会随环境变化而改变
* 外部状态:不可以共享,会随环境变化而改变
*
* 围棋的软件设计:
* 内部状态:颜色,形状,大小;可以共享
* 外部状态:位置;不可以共享
*
* 享元模式的实现:
* FlyWeightFactory 享元工厂类
* 创建并管理享元对象,享元池一般设计成键值对
* FlyWeight抽象享元类
* 通常是一个接口或者抽象类,声明公共方法,这些方法可以向外界提供对象
* 的内部状态,设置外部状态
* ConcreteFlyWeight具体享元类
* 为内部状态提供成员变量进行存储
* UnshardConcreteFlyWeight非共享享元类
* 不能被共享的子类可以设计成非共享享元类
*
* 场景:线程池,数据库连接池
* String类的设计也是享元模式
*
* 节约内存空间,外部状态相对独立,不影响内部状态
* 模式较为复杂,读取外部状态额外增加运行的时间,时间换空间
*/
public class FlyWeightClient {//轻量级
public static void main(String[] args) {
new FlyWeightClient().play();
}
void play (){
String black = "black";
String white = "white";
ChessFlyWeight blackChess = ChessFlyWeightFactory.getChess(black);
blackChess.display(new Position(2,3));//外部状态,由外部传来
ChessFlyWeight whiteChess = ChessFlyWeightFactory.getChess(white);
whiteChess.display(new Position(2,3));
}
}
/**
* 享元类
*/
interface ChessFlyWeight {
void setColor(String color);
String getColor();
void display(Position p);
}
/**享元工厂*/
class ChessFlyWeightFactory {
//享元池
private static Map<String, ChessFlyWeight> map =
new HashMap<String, ChessFlyWeight>();
public static ChessFlyWeight getChess (String color) {
if (map.get(color)!= null) {
return map.get(color);
}
ChessFlyWeight c = new ConcreteChess(color);
map.put(color, c);
return c;
}
}
/** 具体的享元类 */
class ConcreteChess implements ChessFlyWeight{
private String color;
public ConcreteChess(String color) {
super();
this.color = color;
}
public void setColor(String color) {
this.color = color;
}
public String getColor() {
return color;
}
public void display(Position p) {
Pr.pr("棋子的颜色{ "+getColor()+" }");
Pr.pr("显示在指定的地方:{x:"+p.getX()+", "+"y:"+p.getY()+"}");
}
}
/**
* 坐标类 UnsharedConcreteFlyWeight
* 表示外部状态
*/
class Position{
private int x,y;
public Position(int x, int y) {
super();
this.x = x;
this.y = y;
}
public int getX() {
return x;
}
public void setX(int x) {
this.x = x;
}
public int getY() {
return y;
}
public void setY(int y) {
this.y = y;
}
}
- 代理模式
/**
* 代理模式
* 通过代理,控制对象的访问
* 可以详细控制访问某个类,对象的方法,在调用这个方法前做前置处理
* 从而实现将统一流程代码放到代理类中处理
*
* 核心角色
* 抽象角色:定义代理角色和真是角色的公共对外方法
* 真实角色:实现抽象角色,定义真实角色所在实现的业务逻辑供代理角色调用,关注真正的业务逻辑
* 代理角色:实现抽象角色,是真实角色的代理,通过真实角色的业务逻辑方法来实现抽象方法,并可以附加自己的操作
*
* 将统一的流程控制放到代理角色中处理
*
* 调用这个方法后做后置处理(即AOP的微观实现)
*/
public class StaticProxyClient {
public static void main(String[] args) {
Singer singer = new Singer();
Action proxy = new SingerProxy(singer);
StaticProxyClient client = new StaticProxyClient();
client.organize(proxy);
}
/** 组织演唱会 */
void organize(Action action) {
action.contract();
action.sing();
action.getMoney();
}
}
/** 打印输出 */
class Pr {
public static void pr(String content) {
System.out.println(content);
}
}
/** 定义抽象类,即接口 */
interface Action{
void contract();//签合同
void sing(); //唱歌
void getMoney();//收款
}
/** 定义真实角色 - 歌手 */
class Singer implements Action{
public void sing() {
Pr.pr("歌手唱歌");
}
public void contract() {
Pr.pr("歌手签合同");
}
public void getMoney() {
Pr.pr("歌手获得尾款");
}
}
/** 定义代理类 */
class SingerProxy implements Action{
private Singer singer;
public SingerProxy( Singer singer) {
this.singer = singer;
}
public void contract() {
Pr.pr("我是代理,我来签合同");
}
public void sing() {
Pr.pr("代理完成任务,接下来:");
singer.sing();
}
public void getMoney() {
Pr.pr("我是代理,我来收尾款");
singer.getMoney();
}
}
6、结语
学习积累