# DesignPatternsStudy
**Repository Path**: LiuLinXi/DesignPatternsStudy
## Basic Information
- **Project Name**: DesignPatternsStudy
- **Description**: 大话设计模式
- **Primary Language**: Unknown
- **License**: Not specified
- **Default Branch**: master
- **Homepage**: None
- **GVP Project**: No
## Statistics
- **Stars**: 0
- **Forks**: 0
- **Created**: 2019-05-22
- **Last Updated**: 2020-12-19
## Categories & Tags
**Categories**: Uncategorized
**Tags**: None
## README
# 设计模式笔记
## 1.简单工厂模式
- 使用一个单独的类去负责创建类的实例,这个单独的类就是一个工厂
### 示例
```java
package pattern1;
/**
* 运算工厂
*
* @author wdl
*/
public class OperationFactory {
/**
* 根据输入的符号创建不同的对象
* @param operate 输入运算符
* @return 返回创建的对象
*/
public static AbstractOperation createOperation(String operate) {
AbstractOperation operation = null;
switch (operate) {
case "+":
operation = new OperationAdd();
break;
case "-":
operation = new OperationSub();
break;
case "*":
operation = new OperationMul();
break;
case "/":
operation = new OperationDiv();
break;
default:
}
return operation;
}
}
```
## 2.策略模式
- 定义了算法家族,分别封装起来,让它们之间可以相互转换,此模式让算法的变化,不会影响到用算法的客户
### 示例
- 算法完成的工作相同,但是实现不同,可以以相同的方式调用不同的算法
- 策略模式的Strategy层为Context定义了一系列可以重用的算法或行为
- 通过Context控制算法的调用
```java
package pattern2;
///**
// * @author wdl
// */
//public class CashContext {
// private CashSuper cashSuper;
//
// /**
// * 通过构造方法传入具体的收费策略
// * @param cashSuper 收费策略
// */
// public CashContext(CashSuper cashSuper) {
// this.cashSuper = cashSuper;
// }
//
// /**
// * 根据不同收费策略获得结构
// * @param money 输入金额
// * @return 返回具体收费策略的收费金额
// */
// public double getResult(double money) {
// return cashSuper.acceptCash(money);
// }
//}
/**
* 结合简单工厂的Context类
*
* @author wdl
*/
public class CashContext {
private CashSuper cashSuper = null;
public CashContext(int type) {
switch (type) {
//普通收费
case 1:
cashSuper = new CashNormal();
break;
//8折优惠
case 2:
cashSuper = new CashRate(0.8);
break;
//满300-100
case 3:
cashSuper = new CashReturn(300, 100);
break;
default:
}
}
public double getResult(double money) {
return cashSuper.acceptCash(money);
}
}
```
- 比较前面的工厂模式,工厂模式需要暴露两个类CashSuper与CashFactory,策略只需要暴露CashContext
## 3.装饰模式
- 动态的给一个对象添加一些额外的职责,就增加功能来说,装饰模式比生成子类更为灵活
### 示例
Component类
```java
public abstract class Component{
public abstract void opertion();
}
```
ConcreteComponent类
```java
public ConcreteComponent extents Component{
@overrive
public void opertion(){
System.out.print("具体对象的具体操作");
};
}
```
Decorator类
继承Component,从外类对于Component进行功能扩展
```java
abstract class Decorator extents Component{
protected Component component;
//设置Component
public void setComponet(Component component){
this.component=component;
}
@overrive
public void opertion(){
//如果被装饰对象Component不为空则调用被装饰Component的操作,即主要职责
if(component!=null){
component.opertion;
}
};
}
```
ConreteDecorator类
具体的装饰对象,给Component添加职责
```java
class ConreteDecoratorA extents Decorator{
private String state;
@overrive
public void opertion(){
//完成被装饰对象的主要职责
super.opertion();
//这里执行了装饰A特有的方法,相当于对于Component进行了装饰
state="new State";
addOpertion();
System.out.print("具体装饰对象A的具体操作");
};
public void addOpertion(){
//....
}
}
```
具体装饰过程
```java
ConcreteComponent c=new ConcreteComponent();
ConreteDecoratorA dA=new ConreteDecoratorA();
dA.setComponent(c);
dA.opertion();
```
- 装饰模式利用setComponent来对于被装饰对象进行封装。这样每个装饰对象的具体实现就和如何使用这个对象分离了,每个装饰对象只要关心自己的功能,不需要关心自己是如何被添加到对象链中的。
### 优点
- 将类中的装饰功能从类中搬除,这样可以简化原有的类
- 有效的把类的核心职责和装饰功能区分开。而且可以去除相关类中重复的装饰功能。
## 4.代理模式
- 代理模式是指为其它对象提供一种代理以控制对这个对象的访问
### 示例
定义一个实体和代理共用的接口
```java
/**
* @author wdl
* 代理接口
*/
public interface IGiveGift {
/**
* 送样娃娃
*/
void giveDolls();
/**
* 送花
*/
void giveFollowers();
}
```
实体的类定义代理代表的真实实体
```java
/**
* 追求者
*
* @author wdl
*/
public class PurSuit implements IGiveGift {
SchoolGirl schoolGirl;
public PurSuit(SchoolGirl schoolGirl) {
this.schoolGirl = schoolGirl;
}
@Override
public void giveDolls() {
System.out.println(schoolGirl.getName() + "这是送你的洋娃娃");
}
@Override
public void giveFollowers() {
System.out.println(schoolGirl.getName() + "这是送你的花");
}
}
```
Proxy代理通过引用来使得代理可以访问实体,并且实现相同的接口,使得代理可以用来替代实体类
```java
/**
* 代理
* 娇娇不认识追求者,但是可以通过代理得到追求者送的礼物
*
* @author wdl
*/
public class Proxy implements IGiveGift {
/**
*实体类的引用
*/
PurSuit purSuit;
public Proxy(SchoolGirl schoolGirl) {
purSuit = new PurSuit(schoolGirl);
}
/**
* 在实际的方法中去调用”追求者类“中的方法
*/
@Override
public void giveDolls() {
purSuit.giveDolls();
}
@Override
public void giveFollowers() {
purSuit.giveFollowers();
}
}
```
### 适用场合
- 远程代理:为了一个对象在不同的地址空间提供局部代表。这样就可以隐藏一个对象存在于不同地址空间的事实;
- 虚拟代理:根据需要创建开销很大的对象。通过它来存放实例化很长时间的真实对象;
例如:打开很大的HTML网页,里面有许多图片文字,但是你还是可以快速的打开,之后会看到网页的加载,就是虚拟代理存储了尺寸代替了真实的数据;
- 安全代理:控制真实对象的访问权限;
- 智能指引:当调用真实对象时,代理处理另外一些事情。
## 5.工厂方法模式
- 比较前面的简单工厂模式,工厂模式为每一个运算创建一个工厂,而不是通过一个工厂控制
- 简单工厂模式最大的优点在于工厂类中包含必要的逻辑判断,可以根据客户端传入运算符动态选择实例化相关类,对于客户端来说,去除了与具体产品的依赖,但是需要增加时需要修改工厂类中的case条件,违背了对扩展开放对修改关闭的原则
- 工厂方法模式,定义了一个用于创建对象的接口,让子类决定实例化哪一个类。工厂方法使得一个类的实例化延迟到其子类。
- 工厂方法中客户端需要决定实例化哪个工厂来实现运算
### 示例
```java
/**
* 各个实例的工厂
* @author wdl
*/
public class Factory {
}
/**
* 加法工厂
*/
class AddFactory implements IFactory{
@Override
public AbstractOperation createOperation() {
return new OperationAdd();
}
}
/**
* 减法工厂
*/
class SubFactory implements IFactory{
@Override
public AbstractOperation createOperation() {
return new OperationSub();
}
}
/**
* 乘法工厂
*/
class MulFactory implements IFactory{
@Override
public AbstractOperation createOperation() {
return new OperationMul();
}
}
/**
* 除法工厂
*/
class DivFactory implements IFactory{
@Override
public AbstractOperation createOperation() {
return new OperationDiv();
}
}
```
使用:
```java
/**
* 工厂方法模式
* @author wdl
*/
public class FactoryPattern {
public static void main(String[] args) {
IFactory operFactory=new AddFactory();
AbstractOperation addOperation=operFactory.createOperation();
addOperation.numberA=10;
addOperation.numberB=20;
System.out.println(addOperation.getResult());
}
}
```
## 6.原型模式
- 用原型实例创建对象的种类,并通过拷贝这些原型创建新的对象
- 原型模式其实就是从一个对象再创建另一个可定制的对象,而且不需要知道任何创建的细节
- java中可以直接实现*Cloneable* 接口来实现
### 示例
```java
/**
* 通过实现Cloneable接口来实现克隆
*/
public class Resume implements Cloneable {
private String name;
private String company;
public Resume(String name){
this.name=name;
}
public void setCompany(String company){
this.company=company;
}
public void displayCompany(){
System.out.println(company);
}
@Override
protected Object clone() {
Object clone = null;
try {
clone = super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}
return clone;
}
}
```
使用:
```java
/**
* @author wdl
*/
public class ResumePrototype {
public static void main(String[] args) {
Resume resume=new Resume("小菜");
resume.setCompany("今日头条");
Resume resume1= (Resume) resume.clone();
resume1.setCompany("google");
Resume resume2= (Resume) resume.clone();
resume2.setCompany("BaiDu");
resume.displayCompany();
resume1.displayCompany();
resume2.displayCompany();
}
}
```
## 7.模板方法模式
- 定义一个操作中的算法的骨架,而将一些步骤延迟到子类中。模版方法使得子类可以不改变一个算法的结构即可重新定义该算法的某些特定步骤
- 模板方法模式是通过把不变行为搬移到超类,去除子类中的重复代码来体现优势
- 模板方法模式提供了一个很好的代码复用的平台
- 当不变和变化的代码杂和在子类的实现中,不变的代码在子类中重复出现,可以通过模板方法模式把这些不变的行为搬移到单一的地方,这样帮助子类摆脱重复的不变行为的纠缠
### 示例
抽象的模板方法实现骨架:
```java
/**
* 定义一个抽象的模板
* @author wdl
*/
public abstract class AbstractClass {
/**
* 将一些抽象的行为放到子类去实现
*/
protected abstract void primitiveOperation1();
/**
* 将一些抽象的行为放到子类去实现
*/
protected abstract void primitiveOperation2();
/**
* 模板方法,给出逻辑的骨架,而逻辑的组成是一些相应的抽象操作,它们被延迟到子类去实现
*/
public final void templateMethod(){
System.out.println("开始");
primitiveOperation1();
primitiveOperation2();
System.out.println("完成");
}
}
```
子类实现具体的方法:
```java
/**
* @author wdl
*/
public class ConcreteClassA extends AbstractClass{
@Override
protected void primitiveOperation1() {
System.out.println("具体类A实现方法1");
}
@Override
protected void primitiveOperation2() {
System.out.println("具体类A实现方法2");
}
}
/**
* @author wdl
*/
public class ConcreteClassB extends AbstractClass {
@Override
protected void primitiveOperation1() {
System.out.println("具体类B实现方法1");
}
@Override
protected void primitiveOperation2() {
System.out.println("具体类B实现方法2");
}
}
```
```java
/**
* p90
* 模板方法模式
* @author wdl
*/
public class TemplateMethodPattern {
public static void main(String[] args) {
AbstractClass c;
System.out.println("具体实现类A:");
c=new ConcreteClassA();
c.templateMethod();
System.out.println("\n具体实现类B:");
c=new ConcreteClassB();
c.templateMethod();
}
}
```
## 8.外观模式
- 为子系统的接口提供一个一致的界面,此模式定义了一个高层接口,这个接口使得这一子系统更加容易使用。
### 示例
子系统:
```java
/**
* 子系统1
* @author wdl
*/
public class SubSystemOne {
public void methodOne(){
System.out.println("子系统方法1");
}
}
/**
* 子系统2
* @author wdl
*/
public class SubSystemTwo {
public void methodTwo(){
System.out.println("子系统方法2");
}
}
/**
* 子系统3
* @author wdl
*/
public class SubSystemThree {
public void methodThree(){
System.out.println("子系统方法3");
}
}
```
外观类:
```java
/**
* 外观类
*
* 了解子系统的方法和属性,进行组合方便外部调用
*
* @author wdl
*/
public class Facade {
private SubSystemOne subSystemOne;
private SubSystemTwo subSystemTwo;
private SubSystemThree subSystemThree;
public Facade() {
subSystemOne = new SubSystemOne();
subSystemTwo = new SubSystemTwo();
subSystemThree = new SubSystemThree();
}
public void methodA() {
System.out.println("\n方法组合A");
subSystemOne.methodOne();
subSystemTwo.methodTwo();
subSystemThree.methodThree();
}
public void methodB() {
System.out.println("\n方法组合B");
subSystemThree.methodThree();
subSystemTwo.methodTwo();
}
}
```
客户端调用:
```java
/**
* p103
* 外观模式
* @author wdl
*/
public class FacadePattern {
public static void main(String[] args) {
Facade facade=new Facade();
facade.methodA();
facade.methodB();
}
}
```
### 使用场景
1. 设计初期阶段,应该将不同的层次分离,比如数据访问层、数据层、业务逻辑层等,层与层之间建立外观模式
2. 开发阶段,子系统往往因为不断的重构演化而变得复杂,增加外观模式Facade可以提供一个简单的接口,减少之间的依赖
3. 在维护一个大型的遗留项目时,项目已经很难维护和扩展了,为新系统提供一个外观Facade类,来提供实际粗糙或者高度复杂的遗留代码的比较清晰的接口,让新系统与Facade对象交互,Facade类与遗留代码进行复杂的交互工作
## 9.建造者模式
- 建造者模式,将一个复杂对象的构建和表示分离,使得同样的构建过程可以构建不同的表示
- 建造者模式是当在创建一个复杂对象的算法应该独立于该对象的组成部分以及它们的装配方式时适用
### 示例
产品类:
```java
/**
* 产品类,由多个零件组成
*
* @author wdl
*/
public class Product {
List parts = new ArrayList<>();
public void add(String part) {
parts.add(part);
}
public void show() {
System.out.println("\n产品构建----");
for (String part : parts) {
System.out.println(part);
}
}
}
```
抽象的建造者:
```java
/**
* 抽象的构建者
* 确定产品由两个部件PartA和PartB
* @author wdl
*/
public abstract class Builder {
/**
* 构建部件A
*/
public abstract void buildPartA();
/**
* 构建部件B
*/
public abstract void buildPartB();
/**
* 得到产品结果
* @return 得到产品构建后的结果
*/
public abstract Product getResult();
}
```
具体的建造者:
```java
/**
* 具体的构建者1
* @author wdl
*/
public class ConcreteBuilder1 extends Builder{
private Product product=new Product();
/**
* 构建具体的两个部件
*/
@Override
public void buildPartA() {
product.add("部件X");
}
@Override
public void buildPartB() {
product.add("部件Y");
}
@Override
public Product getResult() {
return product;
}
}
```
指挥建造过程:
```java
/**
* 指挥者类
* @author wdl
*/
public class Director {
/**
* 指挥构建的过程
* @param builder 构建的产品
*/
public void buildProduct(Builder builder){
builder.buildPartA();
builder.buildPartB();
}
}
```
适用:
```java
/**
* p112
* 建造者模式
* @author wdl
*/
public class BuilderPattern {
public static void main(String[] args) {
Director director=new Director();
Builder builder1=new ConcreteBuilder1();
Builder builder2=new ConcreteBuilder2();
//指挥者构建产品
director.buildProduct(builder1);
Product product1=builder1.getResult();
product1.show();
director.buildProduct(builder2);
Product product2=builder2.getResult();
product2.show();
}
}
```
## 10.观察者模式
- 观察者模式又称为发布-订阅模式(Publish/Subscribe)
- 观察者模式定义了一种一对多的依赖关系,让多个观察者对象同事监听某个主题对象。这个主题对象在状态发生变化时,通知所有观察者,使它们能够自动更新自己
### 示例
```java
/**
* 主题即抽象的通知者
* @author wdl
*/
public abstract class Subject {
private List observers=new ArrayList<>();
//增加观察者
public void attach(Observer observer){
observers.add(observer);
}
//移除观察者
public void detach(Observer observer){
observers.remove(observer);
}
//通知
public void Notify(){
for (Observer observer:observers){
observer.update();
}
}
}
```
```java
/**
* 抽象的观察者
*
* @author wdl
*/
public abstract class Observer {
public abstract void update();
}
```
```java
/**
* 具体的通知者
* @author wdl
*/
public class ConcreteSubject extends Subject{
private String subjectState;
public String getSubjectState() {
return subjectState;
}
public void setSubjectState(String subjectState) {
this.subjectState = subjectState;
}
}
```
```java
/**
* 具体的观察者
* @author wdl
*/
public class ConcreteObserver extends Observer {
private String name;
private String observerState;
private ConcreteSubject subject;
public ConcreteObserver(String name, ConcreteSubject subject) {
this.name = name;
this.subject = subject;
}
@Override
public void update() {
observerState=subject.getSubjectState();
System.out.println(name+"观察者的状态是"+observerState);
}
public ConcreteSubject getSubject() {
return subject;
}
public void setSubject(ConcreteSubject subject) {
this.subject = subject;
}
}
```
使用:
```java
/**
* 观察者模式
* @author wdl
*/
public class ObserverPattern {
public static void main(String[] args) {
ConcreteSubject subject=new ConcreteSubject();
//增加观察者
subject.attach(new ConcreteObserver("X",subject));
subject.attach(new ConcreteObserver("Y",subject));
subject.attach(new ConcreteObserver("Z",subject));
//改变状态
subject.setSubjectState("ABC");
//发起通知
subject.Notify();
}
}
```
### 不足
- 观察者模式不足的地方:将一个系统分割成相互协作的类,需要维护相关对象间的一致性,使得各个类的耦合度较高
- 通知者需要知道观察者的更新方法,存在耦合
### 适用场景
- 当一个对象的改变需要同时改变其它对象
### 事件委托
- 通过事件委托可以改良观察者模式
- 事件委托,解决问题:一个委托可以**搭载多个方法**,所有方法被一次唤起。更重要的是委托可以使得委托对象所搭载的方法并**不需要属于同一个类**,这样我们就可以解开本来通知者与抽象观察者的耦合。
- 委托是一种引用方法的类型,一旦为委托分配了方法,委托将于该方法具有完全相同的行为,委托方法的使用可以向其他任何方法一样,具有参数和返回值。委托可以看做是对函数的抽象,是函数的“类”,委托的实例将代表一个具体的函数。
- Java中委托通过类的反射机制实现
Event类:
```java
/**
* 处理的事件类
* 通过反射获取到执行方法的对象和方法名方法参数
*
* @author wdl
*/
public class Event {
/**
* 要执行方法的对象
*/
private Object object;
/**
* 要执行方法的方法名
*/
private String methodName;
/**
* 要执行方法的参数
*/
private Object[] params;
public Object getObject() {
return object;
}
public void setObject(Object object) {
this.object = object;
}
public String getMethodName() {
return methodName;
}
public void setMethodName(String methodName) {
this.methodName = methodName;
}
public Object[] getParams() {
return params;
}
public void setParams(Object[] params) {
this.params = params;
}
/**
* 要执行方法的参数类型
*/
private Class[] paramTypes;
public Class[] getParamTypes() {
return paramTypes;
}
public void setParamTypes(Class[] paramTypes) {
this.paramTypes = paramTypes;
}
/**
* 根据参数列表生成参数类型列表
*
* @param params 参数列表
*/
private void contractParamTypes(Object[] params) {
this.paramTypes = new Class[params.length];
//遍历获取每个参数的类型
for (int i = 0; i < params.length; i++) {
this.paramTypes[i] = params[i].getClass();
}
}
/**
* 构造函数
*/
public Event() {
}
public Event(Object object, String methodName, Object[] params) {
this.object = object;
this.methodName = methodName;
this.params = params;
contractParamTypes(params);
}
/**
* 执行该对象的该方法(这里使用反射)
*/
public void invoke() throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
Method method=object.getClass().getMethod(this.getMethodName(),this.getParamTypes());
if (method==null){
return;
}
method.invoke(this.getObject(),this.getParams());
}
}
```
事件处理程序:
```java
/**
* Event的处理类
* @author wdl
*/
public class EventHandler {
private List events;
public EventHandler(){
events=new ArrayList<>();
}
/**
* 添加对象和要执行的方法
* @param object 执行的对象
* @param methodName 执行的方法名
* @param args 方法的参数
*/
public void addEvent(Object object,String methodName,Object...args){
events.add(new Event(object,methodName,args));
}
/**
* 通知所有对象执行方法操作
*/
public void notifyX() throws NoSuchMethodException, IllegalAccessException, InvocationTargetException {
for (Event event:events){
event.invoke();
}
}
}
```
通知者抽象:
```java
/**
* 通知者抽象类
* @author wdl
*/
public abstract class Notifier {
private EventHandler eventHandler=new EventHandler();
public EventHandler getEventHandler() {
return eventHandler;
}
public void setEventHandler(EventHandler eventHandler) {
this.eventHandler = eventHandler;
}
/**
* 添加需要报名放哨的同事
* @param object 需要的同事
* @param methodName 同事执行的方法
* @param args 方法参数
*/
public abstract void addListener(Object object,String methodName,Object...args);
/**
* 通知同事
*/
public abstract void notifyX();
}
```
使用:
这里与观察者模式结合
```java
/**
* 抽象的通知者
* @author wdl
*/
public interface ISubject {
/**
* 通知方法
*/
void notifyX();
/**
* 获取通知状态
* @return 返回当前通知状态
*/
String getSubjectState();
/**
* 设置状态
* @param action 设置状态
*/
void setSubjectState(String action);
}
```
具体的通知者:
```java
/**
* 具体的通知者前台秘书
* @author wdl
*/
public class Secretary extends Notifier implements ISubject{
@Override
public void addListener(Object object, String methodName, Object... args) {
System.out.println("有新的同事委托尽职尽责的放哨人!");
this.getEventHandler().addEvent(object, methodName, args);
}
@Override
public void notifyX() {
try {
this.getEventHandler().notifyX();
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
private String action;
@Override
public String getSubjectState() {
return action;
}
@Override
public void setSubjectState(String action) {
this.action=action;
}
}
```
```java
/**
* 看股票的同事
* @author wdl
*/
public class StockObserver {
private String name;
private ISubject sub;
public StockObserver(String name,ISubject sub){
this.name=name;
this.sub=sub;
}
/**
* 关闭股票继续工作
*/
public void closeStockMarket(){
System.out.println(sub.getSubjectState()+","+name+"关闭股票继续工作");
}
}
```
具体调用:
```java
/**
* 通过事件委托实现观察者模式
*
* @author wdl
*/
public class ObserverPatternByEventCommission {
public static void main(String[] args) {
//前台秘书
Secretary secretary = new Secretary();
//看股票的同事
StockObserver stockObserver = new StockObserver("同事1", secretary);
//看NBA的同事
NBAObserver nbaObserver = new NBAObserver("同事2", secretary);
secretary.addListener(stockObserver, "closeStockMarket");
secretary.addListener(nbaObserver, "closeNBA");
secretary.setSubjectState("老板来了");
secretary.notifyX();
}
}
```
## 11.*抽象工厂模式
- 提供一个创建一系列相关或互相依赖对象的接口,而无需指定它们具体的类
### 好处
- 将产品系列抽象出来,易于交互产品系列,由于具体的工程类例如IFactory factory=new AccessFactory()在一个应用中只需要初始化时出现一次,使得改变应用的具体工厂非常容易,只需要改变具体工厂即可使用不同的产品配置。
- 它让具体的创建实例过程与客户端分离,客户端通过它们的抽象接口操作实例,产品的具体类名也被具体工厂实现分离,不会出现在客户代码中。
## 12.状态模式
- 面向对象设计其实就是希望做到代码的责任分解
- 状态模式:当一个对象的内在状态改变时允许改变其行为,这个对象看起来像是改变了其类
- 状态模式主要解决的是当控制一个对象的状态装换的条件表达式过于复杂时的情况。把状态的判断逻辑转移到表示不同状态的一系列类当中,把复杂的判断逻辑简化
- 其实就是将特定状态相关行为放到一个对象之中,由于所有与状态相关的代码都存在于某个具体的状态中,所以通过定义新的子类就可以容易地增加新的状态和装换,这样就可以消除庞大的判断分支语句
### 示例
工作类修改前:
```java
/**
* 工作类
*
* @author wdl
*/
public class Work {
/**
* 工作的时间点
*/
private int hour;
/**
* 工作是否已经完成
*/
private boolean finishWork;
public void setHour(int hour) {
this.hour = hour;
}
public void setFinishWork(boolean finishWork) {
this.finishWork = finishWork;
}
/**
* 写代码
* 这边逻辑判断比较的复杂,同时破坏了开闭原则
*/
public void writeProgram(){
if (hour<12){
System.out.println("当前时间"+hour+",上午工作,精神百倍");
}else if (hour<13){
System.out.println("当前时间"+hour+",午饭时间,困");
}else if (hour<17){
System.out.println("当前时间"+hour+",下午状态不错,继续努力");
}else {
if (finishWork){
System.out.println("当前时间"+hour+",下班回家");
}else {
if (hour<21){
System.out.println("当前时间"+hour+",加班工作");
}else {
System.out.println("当前时间"+hour+",工作没做完,但是必须回去休息了");
}
}
}
}
}
```
状态模式进行修改:
```java
/**
* 状态的抽象接口
* @author wdl
*/
public interface IState {
void writeProgram(Work work);
}
```
具体的状态:
```java
/**
* 上午的工作状态
* @author wdl
*/
public class ForenoonState implements IState {
@Override
public void writeProgram(Work work) {
if (work.getHour()<12){
System.out.println("当前时间"+work.getHour()+",上午工作,精神百倍");
}else {
//不满足条件则切换到下一个中午的状态
work.setState(new NoonSate());
work.writeProgram();
}
}
}
```
```java
/**
* 中午工作状态
* @author wdl
*/
public class NoonSate implements IState {
@Override
public void writeProgram(Work work) {
if (work.getHour()<13){
System.out.println("当前时间"+work.getHour()+",午饭时间,困");
}else {
//不满足条件就切换到下一个下午的状态
work.setState(new AfternoonState());
work.writeProgram();
}
}
}
```
```java
/**
* 下午的工作状态
* @author wdl
*/
public class AfternoonState implements IState {
@Override
public void writeProgram(Work work) {
if (work.getHour()<17){
System.out.println("当前时间"+work.getHour()+",下午状态不错,继续努力");
}else {
//不满足条件就切换到下一个晚上的工作状态
work.setState(new EveningState());
work.writeProgram();
}
}
}
```
```java
/**
* 夜间工作状态
* @author wdl
*/
public class EveningState implements IState {
@Override
public void writeProgram(Work work) {
if (work.isFinishWork()){
System.out.println("当前时间"+work.getHour()+",下班回家");
}else {
//切换到加班的状态
work.setState(new SleepingState());
work.writeProgram();
}
}
}
```
```java
/**
* 休息的状态
* @author wdl
*/
public class SleepingState implements IState {
@Override
public void writeProgram(Work work) {
if (work.getHour()<21){
System.out.println("当前时间"+work.getHour()+",加班工作");
}else {
System.out.println("当前时间"+work.getHour()+",工作没做完,但是必须回去休息了");
}
}
}
```
工作类用于控制状态的切换
```java
/**
* 工作类
*
* @author wdl
*/
public class Work {
/**
* 工作的时间点
*/
private int hour;
/**
* 工作是否已经完成
*/
private boolean finishWork;
/**
* 工作的状态
*
*/
private IState state;
/**
* 初始化工作状态
* @param state 初始化状态
*/
public Work(IState state){
this.state=state;
}
public void setHour(int hour) {
this.hour = hour;
}
public int getHour() {
return hour;
}
public boolean isFinishWork() {
return finishWork;
}
public void setFinishWork(boolean finishWork) {
this.finishWork = finishWork;
}
public IState getState() {
return state;
}
public void setState(IState state) {
this.state = state;
}
/**
* 写代码
*/
public void writeProgram(){
state.writeProgram(this);
}
}
```
使用
```java
/**
* 加班的示例
* @author wdl
*/
public class OverTime {
public static void main(String[] args) {
//紧急任务,初始化工作状态
Work emergencyProjects=new Work(new ForenoonState());
emergencyProjects.setHour(9);
emergencyProjects.writeProgram();
emergencyProjects.setHour(10);
emergencyProjects.writeProgram();
emergencyProjects.setHour(12);
emergencyProjects.writeProgram();
emergencyProjects.setHour(13);
emergencyProjects.writeProgram();
emergencyProjects.setHour(14);
emergencyProjects.writeProgram();
emergencyProjects.setHour(17);
emergencyProjects.setFinishWork(false);
// emergencyProjects.setFinishWork(true);
emergencyProjects.writeProgram();
emergencyProjects.setHour(22);
emergencyProjects.writeProgram();
}
}
```
### 好处
- 状态模式将与特定状态相关的行为局部化,并且将不同状态的行为分割开来
## 13.适配器模式
- 将一个类的接口转换成客户希望的另外一个接口。Adapter模式使得原本由于接口不兼容而不能工作的类可以一起工作了
- 在软件开发中,系统的数据和行为都是正确的,但是接口不符时,我们应该考虑使用适配器,目的是使控制范围外的一个原有对象与某个接口匹配。
- 适配器模式有两种类型:类适配器模式和对象适配器模式
- 类适配器模式:通过多重继承对一个接口和另一个接口进行适配(C++支持多重继承,Java、C#等语言不支持)
### 示例
首先是大家共同的接口
```java
/**
* ITarget(这是用户所期待的接口,目标可以使抽象或具体的类,也可以是接口)
* @author wdl
*/
public interface ITarget {
/**
* 目标的普通请求
*/
void targetRequest();
}
```
有一个特殊的接口请求是需要适配的
```java
/**
* 需要适配的特殊请求
* @author wdl
*/
public class Adaptee {
public void specificRequest(){
System.out.println("特殊请求");
}
}
```
通过适配器,持有特殊接口的对象,将目标的请求转换为正确的需要的特殊接口的请求
```java
/**
* 适配器,通过内部包装一个Adaptee对象,将目标请求转换为实际的特殊请求
* @author wdl
*/
public class Adapter implements ITarget{
/**
* 建立一个私有的Adaptee对象
*/
private Adaptee adaptee=new Adaptee();
@Override
public void targetRequest() {
//把表面上的调用的targetRequest方法变成实际调用的specificRequest方法
adaptee.specificRequest();
}
}
```
通过适配器就可以调用到需要的接口方法
```java
/**
* p171
* 适配器模式
* @author wdl
*/
public class AdapterPattern {
public static void main(String[] args) {
//对于客户来说调用targetRequest
ITarget target=new Adapter();
target.targetRequest();
}
}
```
### 适用情况
- 适配器模式主要用于希望复用一些现存的类,但是接口又和复用的类不一致的情况。
## 14.备忘录模式
- 在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可以将该对象恢复到原先保存的状态
### 示例
备份类:用于保存备份信息
```java
/**
* 备忘录类
* @author wdl
*/
public class Memento {
private String state;
/**
* 通过构造函数,将相关数据传入
* @param state 相关数据
*/
public Memento(String state){
this.state=state;
}
/**
* 获取相关数据
* @return 相关备份数据返回
*/
public String getState() {
return state;
}
}
```
发起者类:备份恢复备份的发起者
```java
/**
* 发起者类
*
* @author wdl
*/
public class Originator {
private String state;
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
/**
* 创建一个备份
*
* @return 返回备份
*/
public Memento createMemento() {
return new Memento(state);
}
/**
* 恢复备份
* @param memento 备份数据对象
*/
public void getStateFromMemento(Memento memento) {
state = memento.getState();
}
public void show(){
System.out.println(state);
}
}
```
管理类:存储备份和获取备份,是备份的管理
```java
/**
* 管理类
*
* @author wdl
*/
public class Caretaker {
private Memento memento;
//设置和获取备份的方法
public Memento getMemento() {
return memento;
}
public void saveMemento(Memento memento) {
this.memento = memento;
}
}
```
使用
```java
/**
* p180
* 备忘录模式
* @author wdl
*/
public class MementoPattern {
public static void main(String[] args) {
//初始化发起者并设置初始化状态为On
Originator originator=new Originator();
originator.setState("On");
originator.show();
//创建管理者
Caretaker caretaker=new Caretaker();
//管理者保存备份
caretaker.saveMemento(originator.createMemento());
//设置新的状态
originator.setState("Off");
originator.show();
//恢复备份
originator.getStateFromMemento(caretaker.getMemento());
originator.show();
}
}
```
## 15.组合模式
- 将对象组合成树型结构以表示“部分-整体”的层次结构。组合模式使得用户对于单个对象和组合对象的使用具有一致性。
### 示例
Component为组合中的对象声明接口,实现所有类的公共接口的默认行为
```java
/**
* 组合对象的声明接口,在适当的情况下,实现所有类的公共接口的默认行为
* @author wdl
*/
public abstract class BaseComponent {
protected String name;
public BaseComponent(String name) {
this.name = name;
}
/**
* 增加功能
* @param component 组合对象
*/
public abstract void add(BaseComponent component);
/**
* 移除功能
* @param component 组合对象
*/
public abstract void remove(BaseComponent component);
/**
* 显示功能
* @param depth 深度
*/
public abstract void display(int depth);
}
```
Leaf在组合中表示叶子节点对象
```java
/**
* “树叶”没有再增加或减少分支的需要,所以add与remove方法没有意义,
* 但是可以叶子节点和非叶子节点在抽象层的区别,使得它们具有完全一致的接口
*
* @author wdl
*/
public class Leaf extends BaseComponent {
public Leaf(String name) {
super(name);
}
@Override
public void add(BaseComponent component) {
System.out.println("叶子节点不能再增加子节点");
}
@Override
public void remove(BaseComponent component) {
System.out.println("叶子节点没有子节点可以移除");
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
}
}
```
非叶子节点用Composite表示
```java
/**
* 非叶子节点
*
* @author wdl
*/
public class Composite extends BaseComponent {
public Composite(String name) {
super(name);
}
private ArrayList components = new ArrayList<>();
@Override
public void add(BaseComponent component) {
components.add(component);
}
@Override
public void remove(BaseComponent component) {
components.remove(component);
}
@Override
public void display(int depth) {
for (int i = 0; i < depth; i++) {
System.out.print("-");
}
System.out.println(name);
for (BaseComponent component : components) {
component.display(depth + 2);
}
}
}
```
使用
```java
/**
* p189
* 组合模式
* @author wdl
*/
public class CompositePattern {
public static void main(String[] args) {
Composite root=new Composite("root");
root.add(new Leaf("Leaf A"));
root.add(new Leaf("Leaf B"));
Composite composite1=new Composite("Composite1");
composite1.add(new Leaf("Leaf1 A"));
composite1.add(new Leaf("Leaf1 B"));
root.add(composite1);
Composite composite2=new Composite("Composite2");
composite2.add(new Leaf("Leaf2 A"));
composite2.add(new Leaf("Leaf2 B"));
composite1.add(composite2);
root.add(new Leaf("Leaf C"));
Leaf leafD=new Leaf("Leaf D");
root.add(leafD);
root.display(1);
}
}
```
结果
```java
-root
---Leaf A
---Leaf B
---Composite1
-----Leaf1 A
-----Leaf1 B
-----Composite2
-------Leaf2 A
-------Leaf2 B
---Leaf C
---Leaf D
```
### 透明方式与安全方式
- 以上的方式为透明方式,也就是说在Component中声明所有用来管理子类对象的方法,其中包括Add、Remove等。这样实现Component接口的所有子类都具备Add、Remove。这样做的好处就是叶子节点和非叶子节点对于外界没有区别,它们具备完全一致的行为接口,但是也意味着叶子节点实现了没有意义的方法
- 安全方式:在Component接口中不去声明Add、Remove方法,那么子类的Leaf不必实现两个无意义的方法,而在Composite接口中去实现管理子类使用的方法如Add、Remove,这样叶子类与非叶子类实现的接口就是不同的,客户端调用需要做相应的判断,透明度减低但是判断带来了不便。
### 使用场景
- 需求中体现出部分与整体的结构时
- 希望用户忽略组合对象和单个对象的不同,统一的使用组合结构中的所有对象时
## 16.迭代器模式
- 迭代器模式,提供一种顺序访问一个聚合对象中各个元素,而不暴露聚合对象的内部表示
### 适用场景
- 你需要访问一个聚合对象,并且不管对象内部是什么都需要遍历
- 对聚合对象有多种方式遍历(比如从前往后,从后往前等)
### 示例
为遍历不同的聚合结构提供统一的接口
```java
/**
* 为不同的聚合对象提供统一的如开始、下一个、最后一个等统一的接口
* @author wdl
*/
public interface IIterator {
/**
* 获取第一个对象
* @return 第一个对象
*/
Object first();
/**
* 获取下一个对象
* @return 下一个对象
*/
Object next();
/**
* 是否已经到达聚合对象的结尾
* @return 是否结尾
*/
boolean isDone();
/**
* 获取当前对象
* @return 当前对象
*/
Object currentItem();
}
```
Aggregate聚合对象接口
```java
/**
* 聚合对象的接口
* @author wdl
*/
public interface IAggregate {
/**
* 创建迭代器
* @return 迭代器
*/
IIterator createIterator();
}
```
具体的迭代器
```java
/**
* 具体的迭代器
*
* @author wdl
*/
public class ConcreteIterator implements IIterator {
/**
* 定义了一个具体的聚合对象
*/
private ConcreteAggregate aggregate;
private int current = 0;
public ConcreteIterator(ConcreteAggregate aggregate) {
this.aggregate = aggregate;
}
@Override
public Object first() {
return aggregate.getByIndex(0);
}
@Override
public Object next() {
Object ret = null;
current++;
if (current < aggregate.getCount()) {
ret = aggregate.getByIndex(current);
}
return ret;
}
@Override
public boolean isDone() {
return current >= aggregate.getCount();
}
@Override
public Object currentItem() {
return aggregate.getByIndex(current);
}
}
```
具体的聚合对象
```java
/**
* 具体的聚合对象
*
* @author wdl
*/
public class ConcreteAggregate implements IAggregate {
private List