适应设计
iterator 迭代模式
它提供一种方法访问一个容器对象中各个元素,而又不需要暴露改对象的内部细节
//迭代接口
public interface Interator {
public Object next();
public boolean hasNext();
public boolean remove();
}
//具体的迭代器,对集合进行遍历
public class ConcreteIterator implements Iterator {
private Vector vector = new Vector();
public int cursor = 0;
public ConcreteIterator(Vector _vector){
this.vector = _vector;
}
}
public boolean hasNext(){
if(this.cursor == this,vector.size()){
return false;
}else{
return true;
}
}
public Object next(){
Object result = null;
if(this.hasNext()){
result = this.vector.get(this.cursor++);
}else{
result = null;
}
return result;
}
public boolean remove(){
this.vector.remove(this.cursor);
return true;
}
//抽象容器
public interface Aggregate {
public void add(Object object);
public void remove(Object object);
public Iterator iterator();
}
//具体容器
public class ConcreteAggregate implements Aggregate {
private Vector vector = new Vector();
public void add(Object object){
this.vector.add(object);
}
public Iterator iterator() {
return new ConcreteIterator(this.vector);
}
public void remove(Object object){
this.remove(object);
}
}
//场景类
public class Client {
public static void main(String [] args){
Aggregate agg = new ConcreteAggregate();
agg.add('abc');
agg.add('aaa');
agg.add('1234');
Iterator iterator = agg.iterator();
while(iterator.hasNext()){
System.out.println(iterator.next());
}
}
}
adapter 适配器模式(类适配器)
将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作
实现接口,继承调用类
public interface Print {
public abstract void printWeak();
public abstract void printStrong();
}
public class PrintBanner extends Banner implements Print {
public PrintBanner(String string) {
super(string);
}
public void printWeak() {
showWithParen();
}
public void printStrong() {
showWithAster();
}
}
public class Main {
public static void main(String[] args) {
Print p = new PrintBanner("hello");
p.printWeak();
p.printStrong();
}
}
场景
生产中的接口需要对接其他接口
注意事项
设计阶段不要考虑它
adapter 适配器模式(对象适配器)
实现接口,关联接口
public abstract class Print {
public abstract void printWeak();
public abstract void printStrong();
}
public class PrintBanner extends Print{
private Banner banner;
public PrintBanner(String string) {
this.banner = new Banner(string);
}
public void printWeak() {
banner.showWithParen();
}
public void printStrong() {
banner.showWithAster();
}
}
交给子类
template 模板模式
定义一个操作中的算法的框架,而将一些步骤延迟到子类中,使得子类可以不改变一个算法的结构即可重定义该算法的某些特定步骤
public abstract class Xxx {
public abstract void aaa();
public abstract void bbb();
public abstract void ccc();
public void ddd(){
aaa();
bbbb();
ccc();
}
}
注意: 为了防止恶意操作,一般模板方法都加上final关键字,不允许被覆写.
抽象模板中的基本方法尽量设计为protected类型,不需要暴露的属性或方法尽量不要设置为protected类型,尽量不要扩大父类的访问权限
抽象父类提供钩子方法,子类实现决定是否控制行为
父类调用子类的方式(不建议使用)
把子类传递到父类的有参构造中,然后调用
使用反射的方式调用
调用子类的静态方法
factory 工厂模式
public abstract class AbstractHumanFactory {
public abstract<T extends Xxx> T createXxx(Class<T> c);
}
//子类实现
xxx = (Xxx)Class.forName(c.getName()).newInstance();
简单工厂
一个模块仅需要一个工厂类,使用静态方法即可
public class XxxFactory {
public static <T extends Xxx> T createHuman(Class<T> c) {
Xxx xxx = null;
try {
xxx = (Xxx) Class.forName(c.getName()).newInstance();
}catch(Exception e) {
System.out.println("错误: " + e);
}
}
}
生成实例
singleton 单例模式
线程池/缓存/对话框/处理偏好设置/注册表/日志对象/充当打印机,显卡等设备驱动程序的对象
//单线程单例(延迟实例化,需要时(被调用时)才创建对象)
public Singletion {
private static Singletion uniqueInstance;
private Singletion(){}
public static Singletion getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singletion();
}
return uniqueInstance;
}
}
//多线程(性能不是很重要时直接方法加锁)
public Singletion {
private static Singletion uniqueInstance;
private Singletion(){}
public static synchronize Singletion getInstance(){
if(uniqueInstance == null){
uniqueInstance = new Singletion();
}
return uniqueInstance;
}
}
//多线程(急切实例化,静态修饰)
public Singletion {
private static Singletion uniqueInstance = new Singletion();
private Singletion(){}
public static Singletion getInstance(){
return uniqueInstance;
}
}
//多线程(双重检查加锁(不适用1.4及以前版本的java(会失效(volatile))))
public Singletion {
private volatile static Singletion uniqueInstance;
private Singletion(){}
public static Singletion getInstance(){
if(uniqueInstance == null){
synchronize(Singletion.class){
if(uniqueInstance == null){
uniqueInstance = new Singletion();
}
}
}
return uniqueInstance;
}
}
使用多个类加载器,可能导致单例失效
使用jvm1.2或之前版本,要建立注册表,避免被垃圾收集器回收
prototype 原型模式(对象复制)
不通过new关键字来产生一个对象,而是通过对象复制来实现的模式就叫做原型模式
用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象
实现Cloneable接口,重写clone方法
public class PrototypeClass implements Cloneable {
@Override
public PrototypeClass clone() {
PrototypeClass prototypeClass = null;
try {
prototypeClass = (Prototype) super.clone();
}catch(CloneNotSupportedException e) {
//异常处理
}
return prototypeClass;
}
}
缺点:直接在内存中拷贝,构造函数式不会执行的
场景:邮件发送
资源优化场景
类初始化需要消化非常多的资源,这个资源包括数据,硬件资源等
性能和安全要求的场景
通过new产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式
一个对象多个修改者的场景
一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑用原型模式拷贝多个对象供调用者使用
实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过clone方法创建一个对象,然后由工厂方法提供给调用者
浅拷贝引用的成员变量不会被拷贝必须满足的条件: 类的成员变量,可变的引用对象
深拷贝 thing.arrayList = (ArrayList<String>)this.arrayList.clone();
对象的clone与对象内的final关键字是有冲突的,要使用clone方法,类的成员变量上不要增加final关键字
builder 建造者模式(也叫生成器模式)
如果你要调用类中的成员变量或方法,需要在前面加上this关键字
调动父类中的成员变量或者方法显示使用super
ArrayList和HashMap如果定义成类的成员变量,那你在方法中的调用一定要做一个clear的动作,以防数据混乱
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示
Product产品类
Builder抽象建造者
ConcreteBuilder具体建造者
Director导演类
建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗的说就是零件的装配,顺序不同产生的对象也不同
而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序则不是它关心的
abstract factory 抽象工厂
为创建一组相关或相互依赖的对象提供一个接口,而且无需指定它们的具体类
优点:封装
缺点:产品族扩展比较困难
分开考虑
bridge 桥接模式
将抽象和实现解耦,使得两者可以独立地变化
//实现化角色
public interface Implementor {
public void doSomething();
public void doAnything();
}
//具体实现化角色
public class ConcreteImplementor1 implements Implementor {
public void doSomething(){
}
public void doAnything(){
}
}
public class ConcreteImplementor2 implements Implementor {
public void doSomething(){
}
public void doAnything(){
}
}
//抽象化角色
public abstract class Abstraction {
private Implementor imp;
public Abstraction(Implementor _imp){
this.imp = _imp;
}
public void request(){
this.imp.doSomething();
}
public Implementor getImp(){
return imp;
}
}
//具体抽象化角色
public class RefinedAbstraction extends Abstraction {
public RefinedAbstraction(Implementor _imp) {
super(_imp);
}
@Override
public void request(){
super.request();
super.getImp().doAnything();
}
}
//场景类
public class Client {
public static void main(String [] args) {
Implementor imp = new ConcreteImplemnetor1();
Abstraction abs = new RefinedAbstraction(imp);
abs.request();
}
}
使用场景
不希望或不适用使用继承的场景
接口或抽象类不稳定的场景
重用性要求较高的场景
注意事项
类的继承有N层时,可以考虑使用桥梁模式
strategy 策略模式
定义:策略模式定义了算法族,分别封装起来,让它们之间可以相互替换,此模式算法的变化独立于使用算法的客户
设计原则
1:找出应用中可能需要变化之处,把它们独立出来,不要和那些不需要变化的代码混在一起.(把会变化的部分取出并封装)
2:针对接口编程,而不是针对实现编程(实例化时不针对具体的类实现)
3:多用组合,少用继承
利用多态,不同条件不同实现策略,构造函数或者方法中传入接口进行初始化
缺点
策略类数量增多
所有的策略类都需要对外暴露(工厂/代理/享元模式修正)
场景
多个类只有在算法或行为上稍有不同的场景
算法需要自由切换的场景
注意事项
具体策略数量超过4个,则需要考虑使用混合模式,解决策略类膨胀和对外暴露的问题
枚举策略
public enum Calculator {
ADD("+"){
public int exec(int a, int b){
return a+b;
}
}
SUB("-"){
public int exec(int a, int b){
return a-b;
}
}
String value = "";
private Calculator(String _value){
this.value = _value;
}
public String getValue(){
return this.value;
}
public abstract int exec(int a, int b);
}
缺陷
受到枚举类型的限制,在系统开发中,策略枚举一般担当不经常发生变化的角色
一致性
composite 组合模式
将对象组合成树形结构以表示部分-整体的层次结构,使得用户对单个对象和组合对象的使用具有一致性
//抽象构件
public abstract class Component {
public void doSomething(){
}
}
//树枝构件
public class Composite extends Component {
private ArrayList<Component> componentArrayList = new ArrayList<Component>();
public void add(Component component) {
this.componentArrayList.add(component);
}
public void remove(Component component){
this.component.remove(component);
}
public ArrayList<Component> getChaildren(){
return this.componentArrayList;
}
}
//树叶构件
public class Leaf extends Component {
//可以覆写父类方法
public void doSomething(){
}
}
public class Client {
public static void main(String[]args){
Component root = new Component();
root.doSomething();
Composite branch = new Composite();
Leaf leaf = new Leaf();
root.add(branch);
branch.add(leaf);
}
public static void display(Composite root){
for(Component c:root.getChildren()){
if(c instanceof Leaf){
c.doSomethind();
}else {
display((Composite)c);
}
}
}
}
使用场景
维护和展示一部分整体关系的场景,如树形菜单,文件和文件夹管理
从一个整体中能独立出部分模块或功能的场景
decorator 装饰模式
动态地给一个对象添加一些额外的职责,就增加功能来说,装饰模式相比生成子类更为灵活
//抽象构件
public abstract class Component {
public acstract void operate();
}
//具体构件
public class ConcreteComponent extends Component {
@Override
public void operate(){
System.out.println("do something");
}
}
//抽象装饰者
public abstract class Decorator extends Component {
private Component component = null;
public Decorator(Component _component){
this.component = _component;
}
@Override
public void operate(){
this.component.operate();
}
}
//具体的装饰类
public class ConcreteDecorator1 extends Decorator {
//定义被修饰者
public ConcreteDecorator1(Component _component) {
super(_component);
}
//定义自己的修饰方法
private void method1(){
System.out.println();
}
//重写父类的Operation方法
public void operate(){
this.method1();
super.operate();
}
}
//场景类
public static void main(String [] args){
Component component = new ConcreteComponent();
component = new ConcreteComponent1(component);
component = new ConcreteComponent2(component);
component.operate();
}
装饰模式的缺点
层级太深难定位
尽量减少装饰类的数量,以便降低系统的复杂度
装饰模式的使用场景
需要扩展一个类的功能,或给一个类增加附加功能
需要动态的给一个对象增加功能,这些功能可以再动态地撤销
需要为一批的兄弟类进行改装或加装功能
访问数据结构
visitor 访问者模式
封装一些作用于某种数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作
//抽象元素
public abstract class Element {
public abstract void doSomething();
public abstract void accept(IVisitor visitor);
}
//具体元素
public class ConcreteElement1 extends Element {
public void doSomething(){
}
public void accept(Ivisitor visitor) {
visitor.visit(this);
}
}
//抽象访问者
public interface IVisitor {
public void visit(ConcreteElement1 el1);
}
//具体访问者
public class Visitor implements IVisitor {
public void visit(ConcreteElement1 el1){
el1.doSomething();
}
}
//简单工厂
public class ObjectStruture {
public static Element createElement() {
Random rand = new Random();
if(rand.nextInt(100) > 50) {
return new ConcreteElement1();
}else {
return new ConcreteElement2();
}
}
}
//场景类
public class Client {
public static void main(String [] args) {
for(int i = 0; i<10; i++){
Element el = ObjectStruture.createElement();
el.accept(new Visitor());
}
}
}
访问者模式的缺点
具体元素对访问者公布细节
具体元素变更比较困难
违背了依赖倒置原则
抛弃了对接口的依赖,而直接依赖实现类,扩展比较困难
使用场景
一个对象结构包含很多类对象,他们有不同的接口,而你想对这些对象实施一些依赖于其具体类的操作,
也就是说是用迭代器模式已经不能胜任的场景
需要对一个对象结构中的对象进行很多不同并且不相关的操作,而你想避免让这些操作"污染"这些对象的类
业务规则要求遍历多个不同的对象
双分派可以处理java重载是参数的绑定问题,双分派意味着得到执行的操作决定于请求的种类和两个接受者的类型
chain of responsibility 责任链模式
使多个对象都有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,
将这些对象连成一条链,并沿着这条链传递改请求,直到有对象处理它为止
public abstract class Handler {
private Handler nextHandler;
//每个处理者都必须对请求作出处理,子类不可覆写
public final Response handleMessage(Request request){
Response response = null;
//判断是否是自己的处理级别
if(this.getHandlerLevel().equals(request.getRequestLevel())){
response = this.echo(request);
}else {
//不属于自己的处理级别,判断是否有下一个处理者
if(this.nextHandler != null) {
response = this.nextHandler.handleMessage(request);
}else {
//没有适当的处理者,业务自行处理
}
}
return response;
}
//设置下一个处理者是谁
public void setNext(Handler _handler){
this.nextHandler = _handler;
}
//每个处理者都有一个处理级别
protected abstract Level getHandlerLevel();
//每个处理者都必须实现处理任务
protected abstract Response echo(Request request);
}
//具体的处理者
public class ConcreteHandler1 extends Handler {
//定义自己的处理逻辑
protected Response echo(){
//完成处理逻辑
return null;
}
//设置自己的处理级别
protected Level getHandlerLevel() {
//设置自己的处理级别
return null;
}
}
//场景
public class Client {
public static void main(String [] args){
//声明所有的处理节点
Handler handler1 = new ConcreteHandler1();
Handler handler2 = new ConcreteHandler2();
Handler handler3 = new ConcreteHandler3();
handler1.setNext(handler2);
handler2.setNext(handler3);
Response response = handler1.handlerMessage(new Request());
}
}
责任链模式的缺点
一是性能问题,每个请求都是从链头遍历到链尾,特别是在链比较长的时候,性能是一个非常大的问题
二是调试不是很方便,特别是链条比较长,环节比较多的时候,由于采用了类似递归的方式,调试的时候逻辑可能比较复杂
一般的做法是在Handler中设置一个最大节点数量,在setNext方法中判断是否已经是超过其阈值,超过则不允许该链建立,避免无意识地破坏系统性能
简单化
facade 外观模式
public class Facade {
private ClassA a = new ClassA();
private ClassB b = new ClassB();
private ClassC c = new ClassC();
public void methodA(){
this.a.doSomethingA();
}
public void methodB(){
this.a.doSomethingB();
}
public void methodC(){
this.a.doSomethingC();
}
}
优点
减少系统的相互依赖
提高了灵活性
提高安全性
缺点
不符合开闭原则
使用场景
为一个复杂的模块或子系统提供一个供外界访问的接口
子系统相对独立,比如利息的计算问题
预防低水平人员带来的风险扩散
注意事项
一个系统可以有多个门面
子系统可以提供不同访问路径
门面不参与子系统内的业务逻辑(提供封装类)
mediator 中介者模式
用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变他们之间的交互
//通用抽象中介者
public abstract class Mediator {
//定义同事类
protected ConcreteColleague1 c1;
protected ConcreteColleague2 c2;
//通过getter/setter方法把同事类注入进来
public ConcreteColleague1 getC1() {
return c1;
}
public void setC1(ConcreteConlleague1 c1) {
this.c1 = c1;
}
public ConcreteColleague2 getC2(){
return c2;
}
public void setC2(ConcreteColleague2 c2){
this.c2 = c2;
}
//中介者模式的业务逻辑
public abstract void doSomething1();
public abstract void doSomething2();
}
//通用中介者
public class ConcreteMediator extends Mediator {
@Override
public void doSomething1(){
//调用同事类的方法,只要是public方法都可以调用
super.c1.selfMethod1();
super.c2.selfMethod2();
}
public void doSomething2(){
super.c1.selfMethod1();
super.c2.selfMethod2();
}
}
//抽象同事类
public abstract class Colleague {
protected Mediator mediator;
public Colleague(Mediator _mediator){
this.mediator = _mediator;
}
}
//具体同事类
public class ConcreteConlleague1 extends Colleague {
//通过构造函数传递中介者
public ConcreteColleague1(Mediator _mediator) {
super(_mediator);
}
//自有方法self-method
public void selfMethod1(){
//处理自己的业务逻辑
}
//依赖方法 dep-method
public void depMethod1(){
//处理自己的业务逻辑
//自己不能处理的业务逻辑,委托给中介者处理
super.mediator.doSomething1();
}
}
public class ConcreteConlleague2 extends Colleague {
//通过构造函数传递中介者
public ConcreteColleague2(Mediator _mediator) {
super(_mediator);
}
//自有方法self-method
public void selfMethod2(){
//处理自己的业务逻辑
}
//依赖方法 dep-method
public void depMethod2(){
//处理自己的业务逻辑
//自己不能处理的业务逻辑,委托给中介者处理
super.mediator.doSomething2();
}
}
为什么同事类要使用构造函数注入中介者,而中介者使用getter/setter方式注入同事类? 这是因为同事类必须有中介者,而中介者却可以只有部分同事类
缺点:中介者模式的缺点就是中介者会膨胀的很大,而且逻辑复杂,原本N个对象直接相互依赖关系转换为中介者和同事类的依赖关系,同事类越多,中介者的逻辑就越复杂
使用场景:用于多个对象之间机密耦合的情况,类图中出现了蜘蛛网状结构
N个对象之间产生了相互的依赖关系
多个对象有依赖关系,但是依赖的行为尚不确定或者有发生改变的可能,在这种情况下一般建议采用中介者模式,降低变更引起的风险扩散
管理状态
observer 观察者模式
定义:观察者模式定义了对象之间的一对多依赖,这样一来,当一个对象改变状态时,它所有依赖者都会收到通知并自动更新
设计原则
1:为了交互对象之间的松耦合设计而努力
观察者接口,聚合观察者的抽象类,实现此抽象类的子类
聚合类调用观察者子类进行通知
观察者模式的缺点
观察者模式需要考虑一下开发效率和运行效率问题,一个被观察者,多个观察者,开发和调试就会比较复杂
java消息的通知默认是顺序执行,一个观察者卡壳,会影响整体的执行效率,这种情况下一般考虑采用异步的方式
多级触发时的效率更是让人担忧
观察者模式的使用场景
关联行为场景,关联行为是可拆分的
事件多级触发场景
跨系统的消息交换场景,如消息队列的处理机制
注意事项
广播链的问题,一个观察者模式中最多出现一个对象既是观察者也是被观察者,也就是说消息最多转发一次(传递两次)
异步处理问题
memento 备忘录模式
//发起人
public class Originator {
private String state = "";
public String getState() {
return state;
}
public void setState(String state) {
this.state = state;
}
public Memento createMemento() {
return new Memento(this.state);
}
public void restoreMemento(Memento _memento) {
this.setState(_memento.getState());
}
}
//备忘录角色
public class Memento {
private String state = '';
public Memento(String _state) {
this.state = _state;
}
public String getState(){
return state;
}
public void setState(String state) {
this.state = state;
}
}
//备忘录管理员角色
public class Caretaker {
private Memento memento;
public Memento getMemento() {
return memento;
}
public void setMemento(Memento memento) {
this.memento = memento;
}
}
//场景类
public class Client {
Originator originator = new Originaor();
Caretaker caretaker = new Caretaker();
caretaker.setMemento(originator.createMemento());
originator.restoreMemento(caretaker.getMemento());
}
使用场景
需要保存和恢复数据的相关状态场景
提供一个可回滚的操作
需要监控的副本场景中
数据库连接的事务管理就是用的备忘录模式
注意事项
备忘录的生命期,不使用就要立刻删除引用
备忘录的性能,不要在频繁建立备份的场景中使用备忘录模式
clone的备忘录
实现Cloneable
多状态的备忘录模式
public class BeanUtils {
public static HashMap<String, Object> backupProp(Object bean) {
HashMap<String, Object> result = new HashMap<String, Object>();
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for(PropertyDescriptor des : descriptors) {
String fieldName = des.getName();
Method getter = des.getReadMethod();
object fieldValue = getter.invoke(bean, new Object[]{});
if(!fieldName.equalsIgnoreCase("class")){
result.put(fieldName, fieldValue);
}
}
}catch(Exception e) {
}
return result;
}
public static void restoreProp(Object bean, HashMap<String, Object> propMap){
try {
BeanInfo beanInfo = Introspector.getBeanInfo(bean.getClass());
PropertyDescriptor[] descriptors = beanInfo.getPropertyDescriptors();
for (PropertyDescriptor des: descriptors) {
String fieldName = des.getName();
if(propMap.containKey(fieldName)){
Method setter = des.getWriteMethod();
setter.invoke(bean, new Object[]{propMap.get(fieldName)});
}
}
}catch(Exception e){
System.out.println("shit");
e.printStackTrace();
}
}
}
多备份的备忘录
public class Caretaker {
private HashMap<String, Memento> memMap = new HashMap<String, Memento>();
public Memento getMemento(String idx){
return memMap.get(idx);
}
public void setMemento(String idx, Memento memento) {
this.memMap.put(idx, memento);
}
}
注意
要严格限定备忘录的创建,建议增加Map的上限,否则系统很容易产生内存溢出情况
更好的封装
将Memento类封装为内部类
state 状态模式
当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类
//抽象环境角色
public abstract class State {
protected Context context;
public void setContext(Context _context) {
this.context = _contect;
}
public abstract void handle1();
public abstract void handle2();
}
//环境角色
public class ConcreteState1 extends State {
@Override
public void handle1(){
}
@Override
public void handle2(){
super.context.setCurrentState(Context.STATE2);
super.context.handle2();
}
}
public class ConcreteState2 extends State {
@Override
public void handle1(){
super.context.setCurrentState(Context.STATE1);
super.context.handle1();
}
@Override
public void handle2(){
}
}
public class Context {
public final static State STATE1 = new ConcreteState1();
public final static State STATE2 = new ConcreteState2();
private State CurrentState;
public State getCurrentState() {
return CurrentState;
}
public void setCurrentState(State currentState) {
this.CurrentState = currentState;
this.CurrentState.setContect(this);
}
//行为委托
public void handle1() {
this.CurrentState.handle1();
}
public void handle2(){
this.CurrentState.handle2();
}
}
环境角色有两个不成文的约束
把状态对象声明为静态常量,有几个状态对象就声明几个静态常量
环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式
//场景类
public class Client {
public static void main(String [] args) {
Context context = new Context();
context.setCurrentState(new ConcreteState1());
context.handle1();
context.handle2();
}
}
缺点
子类会太多
在数据库中建立一个状态表,然后根据状态执行相应的操作
状态模式的使用场景
行为随状态改变而改变
条件,分支判断语句的替代者
注意事项
对象的状态最好不要超过五个
状态模式+建造者模式
避免浪费
flyweight 享元模式
使用共享对象可有效地支持大量的细粒度的对象
内部状态,对象可共享出来的信息
外部状态,对象得以依赖的一个标记,是随环境改变而改变的,不可以共享的状态
//抽象享元角色
public abstract class Flyweight {
private String intrinsic;
protected final String extrinsic;
public Flyweight(String _extrinsic) {
this.extrinsic = _extrinsic;
}
public abstract void operate();
public String getIntrinsic(){
return intrinsic;
}
public void setIntrinsic(String intrinsic) {
this.intrinsic = intrinsic;
}
}
//具体享元角色
public class ConcreteFlyweight1 extends Flyweight {
public ConcreteFlyweight1(_extrinsic){
super(_extrinsic);
}
public void operate(){
}
}
public class ConcreteFlyweight2 extends Flyweight {
public ConcreteFlyweight2(String _extrinsic) {
super(_extrinsic);
}
public void operate(){
}
}
//享元工厂
public class FlyweightFactory {
//定义一个池容器
private static HashMap<String, Flyweight> pool = new HashMap<String, Flyweight>();
//享元工厂
public static Flyweight getFlyweight(String extrinsic) {
Flyweight flyweight = null;
if(pool.containsKey(extrinsic)){
flyweight = pool.get(extrinsic);
}else {
flyweight = new ConcreteFlyweight1(extrinsic);
pool.put(extrinsic, flyweight);
}
return flyweight;
}
}
缺点
提高了系统的复杂性,需要分离出外部状态和内部状态,且外部状态具有固化特性
场景
系统中存在大量的相似对象
细粒度的对象都具备较接近的外部状态,且内部状态与环境无关,也就是说对象没有特定身份.
需要缓冲池的场景
线程问题
性能平衡
外部状态最好以java的基本类型作为标志,可以大幅地提升效率
proxy 代理模式
为其他对象提供一种代理以控制对这个对象的访问
普通代理
代理类和真是类实现相同的接口,通过代理类去访问真是类
强制代理
指定使用代理类访问
高层模块添加getProxy()
需要使用指定的代理进行访问(要从真是角色查找到代理角色,不允许直接访问真实角色)
虚拟代理
在需要的时候才初始化主题对象,可以避免被代理对象较多而引起的初始化缓慢问题
缺点是需要在每个方法中判断主题对象是否被创建
动态代理
在实现阶段不用关心代理谁,而在运行时阶段才指定代理哪一个对象
InvocationHandler是JDK提供的动态代理接口,对被代理类的方法进行代理
//抽象主题
public interface Subject {
//业务操作
public void doSomething(String str);
}
//真实主题
public class RealSubject implements Subject {
//业务操作
public void doSomething(String str){
System.out.println("do something ---> " + str);
}
}
//动态代理的Handler类
public class MyInvocationHandler implements InvocationHandler {
//被代理的对象
private Object target = null;
//通过构造函数传递一个对象
public MyInvocationHandler(Object _obj) {
this.target = _obj;
}
//代理方法
public Object invoke(Object proxy, Method method, Object[] args){
//执行被代理的方法
return method.invoke(this.target, args);
}
}
//动态代理类
public class DynamicProxy<T> {
public static <T> T newProxyInstance(ClassLoader loader, Class<?> [] interfaces, InvocationHandler h) {
//寻找JoinPoint连接点,aop框架使用元数据定义
if(true) {
//执行一个前置通知
(new BeforeAdvice()).exec();
}
//执行目标,并返回结果
return (T) Proxy.newProxyInstance(loader, interfaces, h);
}
}
//通知接口及实现
public interface IAdvice {
//通知只有一个方法,执行即可
public void exec();
}
public class BeforeAdvice implements IAdvice {
public void exec() {
System.out.println("前置通知被执行.");
}
}
//动态代理的场景类
public class Client {
public static void main(String [] args) {
//定义一个主题
Subject subject = new RealSubject();
//定义一个Handler
InvocationHandler handler = new MyInvocationHandler(subject);
//定义主题的代理
Subject proxy = DynamicProxy.newProxyInstance(subjcet.getClass().getClassLoader(),subject.getClass().getInterfaces(), handler);
//代理的行为
proxy.doSomething("finish");
}
}
//调用链
Client ---> DynamicProxy ---> MyInvocationHandler ---> Subject
用类来表现
command 命令模式
将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能
public interface Command {
void execute();
}
public class Invoker {
private Command command;
public void setCommand(Command command) {
this.command = command;
}
public void action(){
command.execute();
}
}
/**
* 具体的命令
*/
public class SubCommand implements Command {
DoInter doInter;
public SubCommand(DoInter doInter) {
this.doInter = doInter;
}
@Override
public void execute() {
doInter.action();
}
}
//任务接口
public interface DoInter {
void action();
}
//具体的任务
public class InterClass implements DoInter {
@Override
public void action() {
System.out.println("执行具体任务...");
}
}
//场景类
public class DoMain {
public static void main(String [] args) {
DoInter interClass = new InterClass();
Command command = new SubCommand(interClass);
Invoker invoker = new Invoker();
invoker.setCommand(command);
invoker.action();
}
}
interpreter 翻译者模式
给定一门语言,定义他的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子
//抽象表达式
public abstract class Expression {
public abstract Object interpreter(Context ctx);
}
//终结符表达式
public class TerminalExpression extends Expression {
return null;
}
//非终结符表达式
public NonterminalExpression extends Expression {
public (Expression... expression) {
}
public Object interpreter(Context ctx) {
return null;
}
}
//客户类
public class Client {
public static void main(String[]args){
Context ctx = new Context();
Stack<Expression> stack = null;
for(;;) {
}
Expression exp = stack.pop();
exp.interpreter(ctx);
}
}
缺点
解释器模式会引起类膨胀
解释器模式采用递归调用方法
效率问题
使用场景
重复发生的问题可以使用解释器模式
一个简单语法需要解释的场景
注意事项
尽量不要在重要的模块中使用解释器模式
可以考虑Expression4J/MESP/Jep