创建类型设计:
单例设计模式:
单例设计模式主要保证在程序中只有一个实例存在。减少了系统的开销。常见的单例设计有五种:
-
饿汉式(线程安全,调用效率高,但是不能延时加载。)
public class Demo1 { private static Demo1 demo = new Demo1(); private Demo1(){ } public static Demo1 newDemo(){ return demo; } }
-
懒汉式(线程安全,调用效率不高,但是可以延时加载。)
public class Demo2 { private static Demo2 demo; private Demo2(){ } public static synchronized Demo1 newDemo(){ if(demo == null){ return new Demo2(); } return demo; } }
-
双重检测锁式(由于JVM底层内部模型原因,偶尔会出错。不建议使用)
public class Singleton { private static volatile Singleton instance = null; private Singleton(){} public static Singleton getInstance() { if (instance == null) { synchronized (Singleton.class) { if (instance == null) { instance = new Singleton(); } } } return instance; } }
-
静态内部类式(线程安全,调用效率高,可以延时加载。)
public class Demo4 { private static class Demo4Holder{ public static Demo4 demo = new Demo4(); } private Demo4(){ } public static Demo4 newDemo4(){ return Demo4Holder.demo; } }
-
枚举单例(线程安全,调用效率高,不能延时加载。注意:这种单例设计在反射和反编译的时候出问题,其他的都要通过代码来优化。)
public enum Singleton{
instance;
public void whateverMethod(){}
}
设计选择:
单例对象占用资源少,不需要延时加载:
枚举式 > 饿汉式
单例对象占用资源大,需要延时加载:
静态内部类式 > 懒汉式
工厂设计模式:
有三种工厂模式:
简单工厂模式:
特点
1 它是一个具体的类,非接口 抽象类。有一个重要的create()方法,利用if或者 switch创建产品并返回。
2 create()方法通常是静态的,所以也称之为静态工厂。
缺点
1 扩展性差(我想增加一种面条,除了新增一个面条产品类,还需要修改工厂类方法)
2 不同的产品需要不同额外参数的时候 不支持。
public abstract class Car{
//发动机
public void run();
}
public class BaoMa extends Car{
@Override
public void run(){
System.out.println("宝马牌发动机");
}
}
public class ToLaj extends Car{
@Override
public void run(){
System.out.println("拖拉机发动机");
}
}
//简单工厂
public class SimpleCarsFactory {
public static Car createCar(String name){
if(name.equals("宝马")){
return new BaoMa();
}else if (nameequals("拖拉机")){
return new ToLaj();
} else(){
return null ;
}
}
}
//简单工厂的静态调用方法
public class SimpleCarsFactory {
public static Car createBaoMa(){
return new BaoMa();
}
public static Car createToLaj(){
return new ToLaj();
}
}
工厂方法模式 :
提供一个用于创建对象的接口(工厂接口),让其实现类(工厂实现类)决定实例化哪一个类(产品类),并且由该实现类创建对应类的实例。 (简单的来说就是每个扩展方法进行了实现,并且都只是写在一个类里面。这个样子些近一步进行了解耦,但是这样子会增加文件的数量,阅读不能方便,也给调用者带来不便。)
抽象工厂模式 :
抽象工厂模式的优点:
抽象工厂模式除了具有工厂方法模式的优点外,最主要的优点就是可以在类的内部对产品族进行约束。所谓的产品族,一般或多或少的都存在一定的关联,抽象工厂模式就可以在类内部对产品族的关联关系进行定义和描述,而不必专门引入一个新的类来进行管理。
抽象工厂模式的缺点:
产品族的扩展将是一件十分费力的事情,假如产品族中需要增加一个新的产品,则几乎所有的工厂类都需要进行修改。所以使用抽象工厂模式时,对产品等级结构的划分是非常重要的。
适用场景:
当需要创建的对象是一系列相互关联或相互依赖的产品族时,便可以使用抽象工厂模式。说的更明白一点,就是一个继承体系中,如果存在着多个等级结构(即存在着多个抽象类),并且分属各个等级结构中的实现类之间存在着一定的关联或者约束,就可以使用抽象工厂模式。假如各个等级结构中的实现类之间不存在关联或约束,则使用多个独立的工厂来对产品进行创建,则更合适一点。
interface IProduct1 {
public void show();
}
interface IProduct2 {
public void show();
}
class Product1 implements IProduct1 {
public void show() {
System.out.println("这是1型产品");
}
}
class Product2 implements IProduct2 {
public void show() {
System.out.println("这是2型产品");
}
}
interface IFactory {
public IProduct1 createProduct1();
public IProduct2 createProduct2();
}
class Factory implements IFactory{
public IProduct1 createProduct1() {
return new Product1();
}
public IProduct2 createProduct2() {
return new Product2();
}
}
public class Client {
public static void main(String[] args){
IFactory factory = new Factory();
factory.createProduct1().show();
factory.createProduct2().show();
}
}
原型设计模式:
原型模式有两种克隆方式:浅克隆和深克隆
浅拷贝当原型对象被复制时,只复制它本身和其中包含的值类型的成员变量,而引用类型的成员变量并没有复制。
深拷贝除了对象本身被复制外,对象所包含的所有成员变量也将被复制。
使用场景:
(1)类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等,通过原型拷贝避免这些消耗。
(2)通过new产生的一个对象需要非常繁琐的数据准备或者权限,这时可以使用原型模式。
(3)一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用,即保护性拷贝。
Prototype类需要具备以下两个条件:
(1)实现Cloneable接口。在java语言有一个Cloneable接口,它的作用只有一个,就是在运行时通知虚拟机可以安全地在实现了此接口的类上使用clone方法。在java虚拟机中,只有实现了这个接口的类才可以被拷贝,否则在运行时会抛出CloneNotSupportedException异常。
(2)重写Object类中的clone方法。Java中,所有类的父类都是Object类,Object类中有一个clone方法,作用是返回对象的一个拷贝,但是其作用域protected类型的,一般的类无法调用,因此Prototype类需要将clone方法的作用域修改为public类型。
在于clone()方法上,我们知道该clone()方法是使用Object类的clone()方法,但是该方法存在一个缺陷,它并不会将对象的所有属性全部拷贝过来,而是有选择性的拷贝,基本规则如下:
1、 基本类型
如果变量是基本很类型,则拷贝其值,比如int、float等。
2、 对象
如果变量是一个实例对象,则拷贝其地址引用,也就是说此时新对象与原来对象是公用该实例变量。
3、 String字符串
若变量为String字符串,则拷贝其地址引用。但是在修改时,它会从字符串池中重新生成一个新的字符串,原有值所对应对象保持不变。
前度克隆:
public class Book implements Cloneable { //实现Cloneable是声明的作用
int i = 1;
ArrayList<String> list = new ArrayList<String>();
get/set...
@Override
protected Book clone() throws CloneNotSupportedException {
Book book = (Book)super.clone();
book.list.clone();//添加这一条语句表示也克隆list
return book;
}
}
利用序列化进行深度克隆:
//被克隆的类需要实现Serializable接口不然不能进行深度克隆(Serializable 是对该类序列化的支持,)
public class CloneUtils {
@SuppressWarnings("unchecked")
public static <T extends Serializable> T clone(T obj){
T cloneObj = null;
try {
//写入字节流
ByteArrayOutputStream out = new ByteArrayOutputStream();
ObjectOutputStream obs = new ObjectOutputStream(out);
obs.writeObject(obj);
obs.close();
//分配内存,写入原始对象,生成新对象
ByteArrayInputStream ios = new ByteArrayInputStream(out.toByteArray());
ObjectInputStream ois = new ObjectInputStream(ios);
//返回生成的新对象
cloneObj = (T) ois.readObject();
ois.close();
} catch (Exception e) {
e.printStackTrace();
}
return cloneObj;
}
}
创建者模式 :
是将一个复杂的对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。创建者模式隐藏了复杂对象的创建过程,它把复杂对象的创建过程加以抽象,通过子类继承或者重载的方式,动态的创建具有复合属性的对象。
创建者模式通常包括如下几种角色:
1.建造者角色(Builder)
对复杂对象的创建过程加以抽象,给出一个抽象接口,以规范产品对象的各个组成部分的建造。这个接口规定了要实现复杂对象的哪个部分的创建,但并不涉及具体对象不见的创建。
2.具体创建者角色(ConcreateBuilder)
实现Builder接口,针对不同的业务逻辑,具体化复杂对象的各个部分的创建。在建造过程完成后,提供产品的实例。
3.指导者(Director)
调用具体建造者来创建复杂对象的各个部分,在指导者中不设计具体产品的信息,只负责保证对象各部分完整创建或者按某种顺序创建。
4.产品(Product)
要创建的复杂对象,一般来说包含多个部分。
产品(Product)
/**
* Created by ufenqi lixiuyu.
*/
public class Product {
private List<String> parts = new ArrayList<String>();
public void add(String partName){
parts.add(partName);
}
public void show(){
System.out.println("----产品创建----");
for (String part : parts) {
System.out.println(part);
}
}
}
创建者角色(Builder):
public abstract class Builder {
protected abstract void buildPartA();
protected abstract void buildPartB();
protected abstract void buildPartC();
protected abstract Product getResult();
}
具体创建者角色(ConcreateBuilder)
public class BuilderA extends Builder {
private Product product = new Product();
@Override
protected void buildPartA() {
product.add("partA");
}
@Override
protected void buildPartB() {
product.add("partB");
}
@Override
protected void buildPartC() {
product.add("partC");
}
@Override
protected Product getResult() {
return product;
}
}
public class BuilderB extends Builder {
private Product product = new Product();
@Override
protected void buildPartA() {
product.add("partX");
}
@Override
protected void buildPartB() {
product.add("partY");
}
@Override
protected void buildPartC() {
product.add("partZ");
}
@Override
protected Product getResult() {
return product;
}
}
指导者角色BuilderDirector :
public class BuilderDirector {
private Builder builder = null;
public BuilderDirector(Builder builder){
this.builder = builder;
}
public Product build(){
builder.buildPartA();
builder.buildPartB();
builder.buildPartC();
return builder.getResult();
}
}
产品的创建
//只用关心创建的接口就行了
public class BuilderTest {
public static void main(String[] args) {
BuilderDirector director = new BuilderDirector(new BuilderB());
Product product = director.build();
product.show();
}
}
总结:
1)使用建造者模式的好处:
①使用建造者模式可以使客户端不必知道产品内部组成的细节。
②具体的建造者类之间是相互独立的,这有利于系统的扩展。
③具体的建造者相互独立,因此可以对建造的过程逐步细化,而不会对其他模块产生任何影响。
2)建造者模式的使用场景:
①创建一些复杂对象时,这些对象的内部组成部分之间的建造顺序是稳定的,但对象的内部组成构建面临着复杂的变化。
②要创建的复杂对象的算法,独立于该对象的组成部分,也独立于组成部分的装配方法时。
结构型模式 :
适配器模式:
适配器就是一种适配中间件,它存在于不匹配的二者之间,用于连接二者,将不匹配变得匹配,简单点理解就是平常所见的转接头,转换器之类的存在。
适配器模式有两种:类适配器、对象适配器、接口适配器
前二者在实现上有些许区别,作用一样,第三个接口适配器差别较大。(总结一点就相当于是“转接头”这种 东西,一般使用在系统升级等方面)
代理模式:
**代理模式的定义:**代理模式给某一个对象提供一个代理对象,并由代理对象控制对原对象的引用。通俗的来讲代理模式就是我们生活中常见的中介。
代理模式分为静态代理和动态代理:
静态代理:
第一步:创建服务类接口
public interface BuyHouse {
void buyHosue();
}
第二步:实现服务接口
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("我要买房");
}
}
第三步:创建代理类
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHosue() {
System.out.println("买房前准备");
buyHouse.buyHosue();
System.out.println("买房后装修");
}
}
第四步:编写测试类
public class ProxyTest {
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
buyHouse.buyHosue();
BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
buyHouseProxy.buyHosue();
}
}
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理:
在动态代理中我们不再需要再手动的创建代理类,我们只需要编写一个动态处理器就可以了。真正的代理对象由JDK再运行时为我们动态的来创建。
(使用jdk 自带的方法)
//编写动态处理器
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房前准备");
Object result = method.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
//测试类
public class DynamicProxyTest {
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
//buyHouse.buyHosue();
BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new
Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));
proxyBuyHouse.buyHosue();
}
}
注意 Proxy.newProxyInstance() 方法接受三个参数:
-
*ClassLoader loader:*指定当前目标对象使用的类加载器,获取加载器的方法是固定的
-
*Class<?>[] interfaces:*指定目标对象实现的接口的类型,使用泛型方式确认类型
-
InvocationHandler:
指定``动态处理器,
执行目标对象的方法时,会触发事件处理器的方法
CGLIB代理
CGLIB代理总结: CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
桥接模式:
桥接模式即将抽象部分与它的实现部分分离开来,使他们都可以独立变化。
桥接模式将继承关系转化成关联关系,它降低了类与类之间的耦合度,减少了系统中类的数量,也减少了代码量。(有点像二维的模式)
装饰器模式:
装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能。
package com.ztq.decorator;
/***
* 抽象组件
* @author ZTQ
*
*/
public interface ICar {
void move();
}
//ConcreteComponent 具体构件角色(真实对象)
class Car implements ICar{
@Override
public void move() {
System.out.println("陆地上跑!");
}
}
class SuperCar implements ICar{
private ICar car;
public SuperCar(ICar car){
this.car = car;
}
@Override
public void move() {
car.move();
}
}
//ConcreteDecorator具体装饰角色
class FlyCar extends SuperCar{
public FlyCar(ICar car) {
super(car);
}
public void fly(){
System.out.println("天上飞");
}
@Override
public void move() {
super.move();
fly();
}
}
//ConcreteDecorator具体装饰角色
class WaterCar extends SuperCar{
public WaterCar(ICar car) {
super(car);
}
public void swim(){
System.out.println("水里游");
}
@Override
public void move() {
super.move();
swim();
}
}
//ConcreteDecorator具体装饰角色
class AICar extends SuperCar{
public AICar(ICar car) {
super(car);
}
public void autoMove(){
System.out.println("自动跑");
}
@Override
public void move() {
super.move();
autoMove();
}
}
总结:
装饰模式(Decorator)也叫包装器模式(Wrapper)
装饰模式降低系统的耦合度,可以动态的增加或删除对象的职责,并使得需要装饰的具体构建类和具体装饰类可以独立变化,以便增加新的具体构建类和具体装饰类。
优点:
- 扩展对象功能,比继承灵活,不会导致类个数急剧增加
- 可以对一个对象进行多次装饰,创造出不同行为的组合,得到功能更加强大的对象
- 具体构建类和具体装饰类可以独立变化,用户可以根据需要自己增加新的具体构件子类和具体装饰子类
缺点:
- 产生很多小对象。大量小对象占据内存,一定程度上影响性能
- 装饰模式易于出错,调试排查比较麻烦
装饰模式和桥接模式的区别:
两个模式都是为了解决过多子类对象问题。但他们的诱因不一样。桥接模式是对象自身现有机制沿着多个维度变化,是既有部分不稳定。装饰模式是为了增加新的功能。
外观模式:
外观模式(Facade Pattern),外观模式也称为门面模式,它在开发过程中运用频率非常高,尤其是第三方 SDK 基本很大概率都会使用外观模式。通过一个外观类使得整个子系统只有一个统一的高层的接口,这样能够降低用户的使用成本,也对用户屏蔽了很多实现细节。当然,在我们的开发过程中,外观模式也是我们封装 API 的常用手段,例如网络模块、ImageLoader 模块等 .
public interface Shape {
void draw();
}
-----------------------------------------------------------------------------------------------
public class Rectangle implements Shape {
@Override
public void draw() {
System.out.println("Rectangle::draw()");
}
}
-----------------------------------------------------------------------------------------------
public class Square implements Shape {
@Override
public void draw() {
System.out.println("Square::draw()");
}
}
-----------------------------------------------------------------------------------------------
public class Circle implements Shape {
@Override
public void draw() {
System.out.println("Circle::draw()");
}
}
-----------------------------------------------------------------------------------------------
public class ShapeMaker {
private Shape circle;
private Shape rectangle;
private Shape square;
public ShapeMaker() {
circle = new Circle();
rectangle = new Rectangle();
square = new Square();
}
public void drawCircle(){
circle.draw();
}
public void drawRectangle(){
rectangle.draw();
}
public void drawSquare(){
square.draw();
}
}
--------------------------------------------------------------------------------------------
public class FacadePatternDemo {
public static void main(String[] args) {
ShapeMaker shapeMaker = new ShapeMaker();
shapeMaker.drawCircle();
shapeMaker.drawRectangle();
shapeMaker.drawSquare();
}
}
通俗的话就是将接口进行封装,用户方便调用。)
总结:
外观模式是一个高频率使用的设计模式,它的精髓就在于封装二字。通过一个高层次结构为用户提供统一的 API 入口,使得用户通过一个类型就基本能够操作整个系统,这样减少了用户的使用成本,也能够提升系统的灵活性。
外观类遵循了一个很重要设计模式原则:迪米特原则(最少知识原则),它让客户端依赖于最少的类,直接依赖外观类而不是依赖于所有的子系统类。
优点:
- 对客户程序隐藏子系统细节,因而减少了客户对于子系统的耦合,能够拥抱变化;
- 外观类对子系统的接口封装,使得系统更易于使用;
- 更好的划分访问层次,通过合理使用Facade,可以帮助我们更好地划分访问的层次。有些方法是对系统外的,有些方法是系统内部使用的。把需要暴露给外部的功能集中到外观类中,这样既方便客户端使用,也很好地隐藏了内部的细节。
缺点:
- 外观类接口膨胀,由于子系统的接口都由外观类统一对外暴露,使得外观类的 API 接口较多,在一定程度上增加了用户使用成本;
- 外观类没有遵循开闭原则,当业务出现变更时,可能需要直接修改外观类。
组合模式:
组合模式(Composite Pattern),又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。组合模式依据树形结构来组合对象,用来表示部分以及整体层次。这种类型的设计模式属于结构型模式,它创建了对象组的树形结构。 这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
//文件系统中的节点接口
public interface IFile {
//下面两个方法,相当于类图中operation方法
public void delete();
public String getName();
/* 以上为公共行为,以下为文件夹才有的行为 */
//创建新文件,相当于add方法
public void createNewFile(String name);
//相当于remove方法
public void deleteFile(String name);
//相当于GetChild方法
public IFile getIFile(int index);
}
//文件夹
public class Folder implements IFile{
private String name;
private IFile folder;
private List<IFile> files;
public Folder(String name) {
this(name, null);
}
public Folder(String name,IFile folder) {
super();
this.name = name;
this.folder = folder;
files = new ArrayList<IFile>();
}
public String getName() {
return name;
}
//与File的删除方法不同,先删除下面的文件以及文件夹后再删除自己
public void delete() {
List<IFile> copy = new ArrayList<IFile>(files);
System.out.println("------------删除子文件-------------");
for (IFile file : copy) {
file.delete();
}
System.out.println("----------删除子文件结束-------------");
if (folder != null) {
folder.deleteFile(name);
}
System.out.println("---删除[" + name + "]---");
}
public void createNewFile(String name) {
if (name.contains(".")) {
files.add(new File(name,this));
}else {
files.add(new Folder(name,this));
}
}
public void deleteFile(String name) {
for (IFile file : files) {
if (file.getName().equals(name)) {
files.remove(file);
break;
}
}
}
public IFile getIFile(int index) {
return files.get(index);
}
}
//文件
public class File implements IFile{
private String name;
private IFile folder;
public File(String name,IFile folder) {
super();
this.name = name;
this.folder = folder;
}
public String getName() {
return name;
}
public void delete() {
folder.deleteFile(name);
System.out.println("---删除[" + name + "]---");
}
//文件不支持创建新文件
public void createNewFile(String name) {
throw new UnsupportedOperationException();
}
//文件不支持删除文件
public void deleteFile(String name) {
throw new UnsupportedOperationException();
}
//文件不支持获取下面的文件列表
public IFile getIFile(int index) {
throw new UnsupportedOperationException();
}
}
public class Main {
public static void main(String[] args) {
IFile root = new Folder("我的电脑");
root.createNewFile("C盘");
root.createNewFile("D盘");
root.createNewFile("E盘");
IFile D = root.getIFile(1);
D.createNewFile("project");
D.createNewFile("电影");
IFile project = D.getIFile(0);
project.createNewFile("test1.java");
project.createNewFile("test2.java");
project.createNewFile("test3.java");
IFile movie = D.getIFile(1);
movie.createNewFile("致青春.avi");
movie.createNewFile("速度与激情6.avi");
/* 以上为当前文件系统的情况,下面我们尝试删除文件和文件夹 */
display(null, root);
System.out.println();
project.delete();
movie.getIFile(1).delete();
System.out.println();
display(null, root);
}
//打印文件系统
public static void display(String prefix,IFile iFile){
if (prefix == null) {
prefix = "";
}
System.out.println(prefix + iFile.getName());
if(iFile instanceof Folder){
for (int i = 0; ; i++) {
try {
if (iFile.getIFile(i) != null) {
display(prefix + "--", iFile.getIFile(i));
}
} catch (Exception e) {
break;
}
}
}
}
}
总结:
组合模式解耦了客户程序与复杂元素内部结构,从而使客户程序可以像处理简单元素一样来处理复杂元素。
如果你想要创建层次结构,并可以在其中以相同的方式对待所有元素,那么组合模式就是最理想的选择。本章使用了一个文件系统的例子来举例说明了组合模式的用途。在这个例子中,文件和目录都执行相同的接口,这是组合模式的关键。通过执行相同的接口,你就可以用相同的方式对待文件和目录,从而实现将文件或者目录储存为目录的子级元素
享元模式:
当对象数量太多时,将导致运行代价过高,带来性能下降等问题。享元模式通过共享技术实现相同或相似对象的重用提高系统资源的利用率。本文首先阐述了享元模式要解决的问题和解决问题的理念,然后从实现角度重点说明了该模式的本质,并进一步给出了其所包含的角色和组织结构。
享元模式的本质是分离与共享 : 分离变与不变,并且共享不变。
在享元模式中通常会出现工厂模式,需要创建一个享元工厂来负责维护一个享元池(Flyweight Pool)(用于存储具有相同内部状态的享元对象)。在享元模式中,共享的是享元对象的内部状态,外部状态需要通过环境来设置。在实际使用中,能够共享的内部状态是有限的,因此享元对象一般都设计为较小的对象,它所包含的内部状态较少,这种对象也称为细粒度对象。 享元模式的目的就是使用共享技术来实现大量细粒度对象的复用。
单纯享元模式:在单纯享元模式中,所有的享元对象都是可以共享的,即所有抽象享元类的子类都可共享,不存在非共享具体享元类。
//抽象享元角色类
public interface Flyweight {
//一个示意性方法,参数state是外蕴状态
public void operation(String state);
}
//具体享元角色类
//具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象
//被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,
//在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。
public class ConcreteFlyweight implements Flyweight {
private Character intrinsicState = null;
/**
* 构造函数,内蕴状态作为参数传入
* @param state
*/
public ConcreteFlyweight(Character state){
this.intrinsicState = state;
}
/**
* 外蕴状态作为参数传入方法中,改变方法的行为,
* 但是并不改变对象的内蕴状态。
*/
@Override
public void operation(String state) {
// TODO Auto-generated method stub
System.out.println("Intrinsic State = " + this.intrinsicState);
System.out.println("Extrinsic State = " + state);
}
}
//享元工厂角色类
//享元工厂角色类,必须指出的是,客户端不可以直接将具体享元类实例化,而必须通过一个工厂对象,利用一个factory()方法得到享元对象。
//一般而言,享元工厂对象在整个系统中只有一个,因此也可以使用单例模式。
//当客户端需要单纯享元对象的时候,需要调用享元工厂的factory()方法,并传入所需的单纯享元对象的内蕴状态,由工厂方法产生所需要的
//享元对象。
public class FlyweightFactory {
private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
public Flyweight factory(Character state){
//先从缓存中查找对象
Flyweight fly = files.get(state);
if(fly == null){
//如果对象不存在则创建一个新的Flyweight对象
fly = new ConcreteFlyweight(state);
//把这个新的Flyweight对象添加到缓存中
files.put(state, fly);
}
return fly;
}
}
//客户端类
public class Client {
public static void main(String[] args) {
// TODO Auto-generated method stub
FlyweightFactory factory = new FlyweightFactory();
Flyweight fly = factory.factory(new Character('a'));
fly.operation("First Call");
fly = factory.factory(new Character('b'));
fly.operation("Second Call");
fly = factory.factory(new Character('a'));
fly.operation("Third Call");
}
}
复合享元模式:将一些单纯享元使用组合模式加以组合,可以形成复合享元对象,这样的复合享元对象本身不能共享,但是它们可以分解成单纯享元对象,而后者则可以共享。
//抽象享元角色类
public interface Flyweight {
//一个示意性方法,参数state是外蕴状态
public void operation(String state);
}
//具体享元角色类
//具体享元角色类ConcreteFlyweight有一个内蕴状态,在本例中一个Character类型的intrinsicState属性代表,它的值应当在享元对象
//被创建时赋予。所有的内蕴状态在对象创建之后,就不会再改变了。如果一个享元对象有外蕴状态的话,所有的外部状态都必须存储在客户端,
//在使用享元对象时,再由客户端传入享元对象。这里只有一个外蕴状态,operation()方法的参数state就是由外部传入的外蕴状态。
public class ConcreteFlyweight implements Flyweight {
private Character intrinsicState = null;
/**
* 构造函数,内蕴状态作为参数传入
* @param state
*/
public ConcreteFlyweight(Character state){
this.intrinsicState = state;
}
/**
* 外蕴状态作为参数传入方法中,改变方法的行为,
* 但是并不改变对象的内蕴状态。
*/
@Override
public void operation(String state) {
// TODO Auto-generated method stub
System.out.println("Intrinsic State = " + this.intrinsicState);
System.out.println("Extrinsic State = " + state);
}
}
//复合享元角色类
//复合享元对象是由单纯享元对象通过复合而成的,因此它提供了add()这样的聚集管理方法。由于一个复合享元对象具有不同的聚集元素,
//这些聚集元素在复合享元对象被创建之后加入,这本身就意味着复合享元对象的状态是会改变的,因此复合享元对象是不能共享的。
//复合享元角色实现了抽象享元角色所规定的接口,也就是operation()方法,这个方法有一个参数,代表复合享元对象的外蕴状态。
//一个复合享元对象的所有单纯享元对象元素的外蕴状态都是与复合享元对象的外蕴状态相等的;
//而一个复合享元对象所含有的单纯享元对象的内蕴状态一般是不相等的,不然就没有使用价值了。
public class ConcreteCompositeFlyweight implements Flyweight {
private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
/**
* 增加一个新的单纯享元对象到聚集中
*/
public void add(Character key , Flyweight fly){
files.put(key,fly);
}
/**
* 外蕴状态作为参数传入到方法中
*/
@Override
public void operation(String state) {
Flyweight fly = null;
for(Object o : files.keySet()){
fly = files.get(o);
fly.operation(state);
}
}
}
//享元工厂角色类
//享元工厂角色提供两种不同的方法,一种用于提供单纯享元对象,另一种用于提供复合享元对象。
public class FlyweightFactory {
private Map<Character,Flyweight> files = new HashMap<Character,Flyweight>();
/**
* 复合享元工厂方法
*/
public Flyweight factory(List<Character> compositeState){
ConcreteCompositeFlyweight compositeFly = new ConcreteCompositeFlyweight();
for(Character state : compositeState){
compositeFly.add(state,this.factory(state));
}
return compositeFly;
}
/**
* 单纯享元工厂方法
*/
public Flyweight factory(Character state){
//先从缓存中查找对象
Flyweight fly = files.get(state);
if(fly == null){
//如果对象不存在则创建一个新的Flyweight对象
fly = new ConcreteFlyweight(state);
//把这个新的Flyweight对象添加到缓存中
files.put(state, fly);
}
return fly;
}
}
//客户端类
public class Client {
public static void main(String[] args) {
List<Character> compositeState = new ArrayList<Character>();
compositeState.add('a');
compositeState.add('b');
compositeState.add('c');
compositeState.add('a');
compositeState.add('b');
FlyweightFactory flyFactory = new FlyweightFactory();
Flyweight compositeFly1 = flyFactory.factory(compositeState);
Flyweight compositeFly2 = flyFactory.factory(compositeState);
compositeFly1.operation("Composite Call");
System.out.println("---------------------------------");
System.out.println("复合享元模式是否可以共享对象:" + (compositeFly1 == compositeFly2));
Character state = 'a';
Flyweight fly1 = flyFactory.factory(state);
Flyweight fly2 = flyFactory.factory(state);
System.out.println("单纯享元模式是否可以共享对象:" + (fly1 == fly2));
}
}
总结:
**1、模式适用环境**
在以下情况下可以使用享元模式:
- 一个系统有大量相同或者相似的对象,由于这类对象的大量使用,造成内存的大量耗费;
- 对象的大部分状态都可以外部化,可以将这些外部状态传入对象中(细粒度对象);
- 使用享元模式需要维护一个存储享元对象的享元池,而这需要耗费资源,因此,应当在多次重复使用享元对象时才值得使用享元模式。
2、模式的优点
(1)它可以极大减少内存中对象的数量,使得相同对象或相似对象在内存中只保存一份;
(2)享元模式的外部状态相对独立,而且不会影响其内部状态,从而使得享元对象可以在不同的环境中被共享。
3、模式的缺点
(1)享元模式使得系统更加复杂,需要分离出内部状态和外部状态,这使得程序的逻辑复杂化;
(2)为了使对象可以共享,享元模式需要将享元对象的状态外部化,而读取外部状态使得运行时间变长。
行为型模式 :
##策略模式:
策略模式定义了一系列的算法,并将每一个算法封装起来,而且使他们可以相互替换,让算法独立于使用它的客户而独立变化。
分析下定义,策略模式定义和封装了一系列的算法,它们是可以相互替换的,也就是说它们具有共性,而它们的共性就体现在策略接口的行为上,另外为了达到最后一句话的目的,也就是说让算法独立于使用它的客户而独立变化,我们需要让客户端依赖于策略接口。
这个模式涉及到三个角色:
环境(Context)角色:持有一个Strategy的引用。
抽象策略(Strategy)角色:这是一个抽象角色,通常由一个接口或抽象类实现。此角色给出所有的具体策略类所需的接口。
具体策略(ConcreteStrategy)角色:包装了相关的算法或行为。
//简单的策略模式
//抽象策略类
public interface Strategy {
/**
* 策略方法
*/
public void strategyInterface();
}
-----------------------------------------------------------
//具体策略类
public class ConcreteStrategyA implements Strategy {
@Override
public void strategyInterface() {
//相关的业务
}
}
public class ConcreteStrategyB implements Strategy {
@Override
public void strategyInterface() {
//相关的业务
}
}
------------------------------------------------------------
//环境角色类
public class Context {
//持有一个具体策略的对象
private Strategy strategy;
/**
* 构造函数,传入一个具体策略对象
* @param strategy 具体策略对象
*/
public Context(Strategy strategy){
this.strategy = strategy;
}
/**
* 策略方法
*/
public int contextInterface(int num){
if(num >1000){
return new ConcreteStrategyA().strategyInterface();
}else{
return new ConcreteStrategyB().strategyInterface();
}
}
}
虽然结合简单工厂模式,我们的策略模式灵活了一些,但不免发现在工厂中多了if-else判断,也就是如果增加一个会员类别,我又得增加一个else-if语句,这是简单工厂的缺点,对修改开放。
为了解决这个问题,我们可以采用注解的方法来改造策略者模式;
##模板方法模式:
模板方法模式是一种基于继承的代码复用的行为型模式;在其结构中只存在父类与子类之间的继承关系。通过使用模板方法模式,可以将一些复杂流程的实现步骤封装在一系列基本方法中,在抽象父类中提供一个称之为模板方法的方法来定义这些基本方法的执行次序,而通过其子类来覆盖某些步骤,从而使得相同的算法框架可以有不同的执行结果。
观察者模式:
观察者模式又被称作发布/订阅模式,观察者模式定义了一种一对多的依赖关系,让多个观察者对象同时监听某一个主题对象。这个主题对象在状态发生变化时,会通知所有观察者对象,使它们能够自动更新自己 。
抽象主题(Subject):它把所有观察者对象的引用保存到一个聚集里,每个主题都可以有任何数量的观察者。抽象主题提供一个接口,可以增加和删除观察者对象。
具体主题(ConcreteSubject):将有关状态存入具体观察者对象;在具体主题内部状态改变时,给所有登记过的观察者发出通知。
抽象观察者(Observer):为所有的具体观察者定义一个接口,在得到主题通知时更新自己。
具体观察者(ConcreteObserver):实现抽象观察者角色所要求的更新接口,以便使本身的状态与主题状态协调。
1.Subject 和 Observer 是一个一对多的关系,也就是说观察者只要实现 Observer 接口并把自己注册到 Subject 中就能够接收到消息事件;
2.Java API有内置的观察者模式类:java.util.Observable 类和 java.util.Observer 接口,这分别对应着 Subject 和 Observer 的角色;
3.使用 Java API 的观察者模式类,需要注意的是被观察者在调用 notifyObservers() 函数通知观察者之前一定要调用 setChanged() 函数,要不然观察者无法接到通知;
4.使用 Java API 的缺点也很明显,由于 Observable 是一个类,java 只允许单继承的缺点就导致你如果同时想要获取另一个父类的属性时,你只能选择适配器模式或者是内部类的方式,而且由于 setChanged() 函数为 protected 属性,所以你除非继承 Observable 类,否则你根本无法使用该类的属性,这也违背了设计模式的原则:多用组合,少用继承。
##迭代子模式
迭代子模式又叫游标(Cursor)模式,是对象的行为模式。迭代子模式可以顺序的访问一个聚集中的元素而不必暴露聚集的内部表象(internal representation)。
聚集和JAVA聚集:
多个对象聚在一起形成的总体称为聚集(Aggregate),聚集对象是能够包含一组对象的容器对象。聚集依赖于聚集结构的抽象化,具有复杂化和多样性。数组就是最基本的聚集,也是其他JAVA聚集对象的设计基础。
Java聚集对象时实现了共同的java.util.Collection
接口的对象,是Java语言对聚集概念的直接支持。从1.2版开始,Java语言提供了很多种聚集,包括Vector
、ArrayList
、HashSet
、HashMap
、Hashtable
等,这些都是Java聚集的例子。
迭代子模式具有两种实现方式,分别为白箱聚集于外禀迭代子和黑箱聚集于内禀迭代子。
白箱聚集于外禀迭代子:
如果一个聚集的接口提供了可以用来修改聚集元素的方法,这个接口就是所谓的**宽接口**。
如果聚集对象为所有对象提供同一个接口,也就是宽接口的话,当然会满足迭代子模式对迭代子对象的要求。但是,这样会破坏对聚集对象的封装。这种提供宽接口的聚集叫做**白箱聚集**。聚集对象向外界提供同样的宽接口。
由于聚集自己实现迭代逻辑,并向外部提供适当的接口,使得迭代子可以从外部控制聚集元素的迭代过程。这样一来迭代子所控制的仅仅是一个游标而已,这种迭代子叫做**游标迭代子(Cursor Iterator)**。由于迭代子是在聚集结构之外的,因此这样的迭代子又叫做**外禀迭代子(Extrinsic Iterator)**。
//抽象聚集角色类
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代子对象的接口
* @return
*/
public abstract Iterator createIterator();
}
--------------------------------------------------------------------------------
//聚提聚集角色类
public class ConcreteAggregate extends Aggregate {
private Object[] objArray = null;
/**
* 构造方法,传入聚合对象的具体内容
* @param objArray
*/
public ConcreteAggregate(Object[] objArray) {
this.objArray = objArray;
}
@Override
public Iterator createIterator() {
return new ConcreteIterator(this);
}
/**
* 取值方法,向外界提供聚集元素
* @param index
* @return
*/
public Object getElement(int index) {
if (index < objArray.length) {
return objArray[index];
} else {
return null;
}
}
/**
* 取值方法,向外界提供聚集的大小
* @return
*/
public int size() {
return objArray.length;
}
}
---------------------------------------------------------------------------
//抽象迭代子角色类
public interface Iterator {
/**
* 迭代方法,移动至第一个元素
*/
public void first();
/**
* 迭代方法,移动至下一个元素
*/
public void next();
/**
* 迭代方法,是否为最后一个元素
*/
public boolean isDone();
/**
* 迭代方法,返回当前元素
*/
public Object currentItem();
}
------------------------------------------------------------------------------
//具体迭代子角色类
public class ConcreteIterator implements Iterator {
/**
* 持有被迭代的具体的聚合对象
*/
private ConcreteAggregate agg;
/**
* 内部索引,记录当前迭代到的索引位置
*/
private int index = 0;
/**
* 记录当前索引对象的大小
*/
private int size = 0;
/**
* 构造函数,传入具体的聚合对象,并获取聚合对象大小
* @param agg
*/
public ConcreteIterator(ConcreteAggregate agg) {
this.agg = agg;
this.size = agg.size();
this.index = 0;
}
/**
* 移动至第一个元素
*/
public void first() {
this.index = 0;
}
/**
* 迭代方法,移动到下一个元素
*/
public void next() {
if (this.index < this.size) {
this.index++;
}
}
/**
* 迭代方法,是否是最后一个元素
*/
public boolean isDone() {
return (this.index >= this.size);
}
/**
* 迭代方法,返还当前位置元素
*/
public Object currentItem() {
return this.agg.getElement(this.index);
}
}
------------------------------------------------------------------------
黑箱聚集与内禀迭代子:
如果一个聚集的接口没有提供修改聚集元素的方法,这样的接口就是所谓的窄接口。
聚集对象为迭代子对象提供一个宽接口,而为其他对象提供一个窄接口。换而言之,聚集对象的内部接口应当对迭代子对象适当公开,以便迭代子对象能够对聚集对象有足够的了解,从而可以进行迭代操作。但是,聚集对象应当避免向其他对象提供这些方法,因为其他对象应当经过迭代子对象进行这些工作,而不是直接操控聚集对象。
在Java语言中,实现双重接口的方法就是将迭代子类设计成聚集类的内部成员类。这样迭代子对象可以像聚集对象的内部成员一样访问聚集对象的内部结构。下面给出一个示意性的实现,说明这种双重接口的结构是怎样产生的,以及使用双重接口之后迭代子模式的实现方案。这种同时保证聚集对象的封装和迭代子功能的实现方案叫做黑箱实现方案。
由于迭代子是聚集的内部类,迭代子可以自由访问聚集的元素,所以迭代子可以自行实现迭代功能并控制对聚集元素的迭代逻辑。由于迭代子是在聚集的结构之内定义的,因此这样的迭代子又叫做内禀迭代子(Intrinsic Iterator)。
为了说明黑箱方案的细节,这里给出一个示意性的黑箱实现。在这个实现里,聚集类ConcreteAggregate
含有一个内部成员类ConcreteIterator
,也就是实现了抽象迭代子接口的具体迭代子类,同时聚集并不向外界提供访问自己内部元素的方法。
public abstract class Aggregate {
/**
* 工厂方法,创建相应迭代子对象的接口
* @return
*/
public abstract Iterator createIterator();
}
----------------------------------------------------------------------
public interface Iterator {
/**
* 迭代方法,移动至第一个元素
*/
public void first();
/**
* 迭代方法,移动至下一个元素
*/
public void next();
/**
* 迭代方法,是否为最后一个元素
*/
public boolean isDone();
/**
* 迭代方法,返回当前元素
*/
public Object currentItem();
}
----------------------------------------------------------------------
public class ConcreteAggregate extends Aggregate {
private Object[] objArray = null;
/**
* 构造方法,传入聚合对象的具体内容
*
* @param objArray
*/
public ConcreteAggregate(Object[] objArray) {
this.objArray = objArray;
}
@Override
public Iterator createIterator() {
return new ConcreteIterator();
}
/**
* 内部成员类,具体迭代子类
* @author chenshuaishuai
*
*/
private class ConcreteIterator implements Iterator {
/**
* 内部索引,记录当前迭代到的索引位置
*/
private int index = 0;
/**
* 记录当前聚集对象的大小
*/
private int size = 0;
/**
* 构造函数,设置聚集对象大小和起始索引
*/
public ConcreteIterator() {
this.size = objArray.length;
this.index = 0;
}
/**
* 移动至第一个元素
*/
@Override
public void first() {
this.index = 0;
}
/**
* 迭代方法,移动到下一个元素
*/
@Override
public void next() {
if (this.index < this.size) {
this.index++;
}
}
/**
* 迭代方法,是否是最后一个元素
*/
@Override
public boolean isDone() {
return (this.index >= this.size);
}
/**
* 迭代方法,返还当前位置元素
*/
@Override
public Object currentItem() {
return objArray[this.index];
}
}
}
----------------------------------------------------------------------------
public class Client {
public void operation() {
Object[] objArray = { "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eigth" };
Aggregate agg = new ConcreteAggregate(objArray);
Iterator iterator = agg.createIterator();
while (!iterator.isDone()) {
System.out.println(iterator.currentItem());
iterator.next();
}
}
public static void main(String[] args) {
Client client = new Client();
client.operation();
}
}
##命令模式
命令模式是一个高内聚的模式,将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请 求排队或者记录请求日志,可以提供命令的撤销和恢复功能。
备忘录模式
备忘录(Memento)模式又称标记(Token)模式。GOF给备忘录模式的定义为:在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到原先保存的状态。
备忘模式分类:
1.“白盒”备忘录模式
/**
* 类似白箱备忘录模式
* @author weichyang
*
*/
public class Client {
/**
* 客户端
*
* @param args
*/
public static void main(String[] args) {
int state = 3;
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState(state);
/**
* 创建备忘录对象的 缓存起来
*/
caretaker.saveMemento(originator.creatMementoObject());
/*
* 进行设置重新还原
*/
originator.setState(5);
System.out.println("发起人更改状态:" + originator.getState());
originator.restoreMemento(caretaker.retrieveMemento());
}
}
**
* 管理者 负责管理Caretaker
*
* @author weichyang
*
*/
public class Caretaker {
private Memento memento;
/**
* 备忘录的取值方法
*/
public Memento retrieveMemento() {
return this.memento;
}
/**
* 备忘录的赋值方法
*/
public void saveMemento(Memento memento) {
this.memento = memento;
}
}
/**
* 备忘录
*
* @author weichyang
*
*/
public class Memento {
private int state;
public Memento() {
super();
}
public Memento(int state) {
this.state = state;
System.out.println("备忘录 当前保存 状态:" + state);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
/**
* 发起者
*
* @author weichyang
*
*/
public class Originator {
private int state = 0;
Caretaker caretaker = new Caretaker();
public Memento creatMementoObject() {
return new Memento(state);
}
/**
* 将发起人恢复到备忘录对象所记载的状态
*/
public void restoreMemento(Memento memento) {
this.state = memento.getState();
System.out.println("恢复 备忘录 状态:" + state);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
2.“黑盒”备忘录模式
/**
* 类似黑箱备忘录模式
*
* @author weichyang
*
*/
public class Client {
/**
* 客户端
*
* @param args
*/
public static void main(String[] args) {
int state = 3;
Originator originator = new Originator();
Caretaker caretaker = new Caretaker();
originator.setState(state);
/**
* 创建备忘录对象的 缓存起来
*/
caretaker.saveMemento(originator.creatMementoObject());
/*
* 进行设置重新还原
*/
originator.setState(5);
System.out.println(" 黑箱发起人更改状态:" + originator.getState());
originator.restoreMemento(caretaker.retrieveMemento());
}
}
public interface MemotoIF {
}
/**
* 发起者
* 内部类如何拿到外部类的引用 https://zhidao.baidu.com/question/513464853.html
* 已经外部类如何访问内部类中的成员
* @author weichyang
*
*/
public class Originator {
private int state = 0;
Caretaker caretaker = new Caretaker();
public Memento creatMementoObject() {
return new Memento(state);
}
/**
* 将发起人恢复到备忘录对象所记载的状态
*/
public void restoreMemento(MemotoIF momIf) {
this.setState(((Memento) momIf).getState());
System.out.println("黑箱恢复 备忘录 状态:" + state);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
private class Memento implements MemotoIF {
private int state;
public Memento(int state) {
this.state = state;
System.out.println("黑箱备忘录 当前保存 状态:" + state);
}
public int getState() {
return state;
}
public void setState(int state) {
this.state = state;
}
}
}
/**
* 管理者 负责管理Caretaker
*
* @author weichyang
*
*/
public class Caretaker {
private MemotoIF memento;
/**
* 备忘录的取值方法
*/
public MemotoIF retrieveMemento() {
return this.memento;
}
/**
* 备忘录的赋值方法
*/
public void saveMemento(MemotoIF memento) {
this.memento = memento;
}
}
3.“多重”检查点
前面所给出的白箱和黑箱的示意性实现都是只存储一个状态的简单实现,也可以叫做只有一个检查点。常见的系统往往需要存储不止一个状态,而是需要存储多个状态,或者叫做有多个检查点。 备忘录模式可以将发起人对象的状态存储到备忘录对象里面,备忘录模式可以将发起人对象恢复到备忘录对象所存储的某一个检查点上。
4.”自述历史”模式
所谓“自述历史”模式(History-On-Self Pattern)实际上就是备忘录模式的一个变种。在备忘录模式中,发起人(Originator)角色、负责人(Caretaker)角色和备忘录 (Memento)角色都是独立的角色。虽然在实现上备忘录类可以成为发起人类的内部成员类,但是备忘录类仍然保持作为一个角色的独立意义。在“自述历 史”模式里面,发起人角色自己兼任负责人角色。
(参考)[https://blog.csdn.net/o279642707/article/details/60767258]
##状态模式
状态模式是策略模式的孪生兄弟
在软件开发过程中,应用程序可能会根据不同的情况作出不同的处理。最直接的解决方案是将这些所有可能发生的情况全都考虑到。然后使用if… ellse语句来做状态判断来进行不同情况的处理。但是对复杂状态的判断就显得“力不从心了”。随着增加新的状态或者修改一个状体(if else(或switch case)语句的增多或者修改)可能会引起很大的修改,而程序的可读性,扩展性也会变得很弱。维护也会很麻烦。那么我就考虑只修改自身状态的模式。
状态模式:允许一个对象在其内部状态改变时改变它的行为。对象看起来似乎修改了它的类。
在很多情况下,一个对象的行为取决于一个或多个动态变化的属性,这样的属性叫做状态,这样的对象叫做有状态的(stateful)对象,这样的对象状态是从事先定义好的一系列值中取出的。当一个这样的对象与外部事件产生互动时,其内部状态就会改变,从而使得系统的行为也随之发生变化。
(例子)[https://www.cnblogs.com/haoerlv/p/7777789.html]
##访问者模式
(讲解)[https://blog.csdn.net/u012124438/article/details/70537203]
##中介者模式
(详解)[https://www.cnblogs.com/snaildev/p/7686908.html]
##解释器模式
用的很少 了解