设计模式之禅读书笔记

一.六大设计原则
单一职责原则
应该有且仅有一个原因引起类的变更

  对于接口设计时要做到单一职责

里氏替换原则:只要有父类出现的地方,替换为子类也不会产生任何问题或异常
  

依赖倒置原则:模块间的依赖关系是通过接口或抽象类产生的(面向接口编程)


接口隔离原则
  客户不应该依赖它不需要的接口
  类间的依赖关系应建立在最小的接口上

  尽量使用多个专门的接口


迪米特法则:一个对象应对其他对象有最少的了解
  只和直接朋友交流,朋友间也是有距离的
  一个方法中尽量不引入类中不存在的对象

  减少public方法和属性


开闭原则:对扩展开放,对修改关闭
  通过扩展来实现变化
  不允许出现接口或抽象方法中不存在的public方法


二.设计模式:
1.单例模式:(皇帝)
确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例(单例类不要实现clone接口)
优点:减少开销,设置系统全局访问点,优化和共享资源
缺点:难于扩展,不利于测试
使用场景:

生成唯一序列号的环境;在整个项目中需要一个共享访问点或共享数据;创建一个对象需要消耗的资源过多(IO、数据库),需要定义大量的静态常量和静态方法(如工具类)

最佳实践:

Spring中每个bean默认都是单例的,这样做优点是spring容器可以管理这些bean的生命周期,如果采用prototype,则bean初始化后的管理由j2ee容器


通用代码如下:

public class Singleton{

private static final Singleton singleton = new Singleton();

//私有构造方法,不允许new

private Single(){}

//通过该方法获取实例对象

public static Singleton getSingleton(){

return singleton;

}

}



2.工厂方法模式:(女娲造人)
定义一个创建对象的接口,让子类决定实例化哪个类,工厂方法使一个类的实例化延迟到其子类

优点:良好的封装性,很好的扩展性,屏蔽产品类(调用者只需要关心产品的接口),典型解耦(高层模块只需要知道产品的抽象类)


使用场景:
工厂模式是new一个对象的替代品,生成对象的地方都可以使用(慎重考虑代码的复杂度)

需要灵活的、可扩展的框架时,可以考虑采用工厂模式

可以用在异构项目中


通用代码如下:

1)抽象代码类:

public abstract class Product {    
     //产品类的公共方法
     public void method1(){
             //业务逻辑处理
     }  
     //抽象方法
     public abstract void method2();    
}

2)具体产品类

public class ConcreteProduct1 extends Product {
     public void method2() {
             //业务逻辑处理
     }
}
public class ConcreteProduct2 extends Product {
     public void method2() {
             //业务逻辑处理
     }
}

3)抽象工厂类

public abstract class Creator{

//创建一个产品对象,其输入的参数类型可以自行设置

public abstract <T extends Product> T createProduct(Class<T> c);

}

4)具体工厂类

public class ConcreteCreator extends Creator{

public abstract <T extends Product> T createProduct(Class<T> c){

Product product = null;

try {
                   product = (Product)Class.forName(c.getName()).newInstance();
             } catch (Exception e) {
                    //异常处理
             }
             return (T)product; 

}

}

5)场景类

public class Client {
     public static void main(String[] args) {

Creator creator = new ConcreteCreator();

Product product = creator.createProduct(ConcreteProduct1.class);
     }
}


3.抽象工厂模式(女娲造人)

为创建一组相关或相互依赖的对象提供一个接口,而且无需指定他们具体的类


优点:封装性;产品族内的约束为非公开状态

缺点:产品族难于扩展


使用场景:一个对象族(或一组没有任何关系的对象)都有相同的约束,则可以使用抽象模式

在有多个业务品种、业务分类时,通过抽象工厂模式产生需要的对象是一种很好的解决方法

有N个产品族,在抽象工厂类中就有N个创建方法

有M个产品等级就应该有M个实现工厂,在每个实现工厂中实现不同产品族的生产任务


最佳实践:涉及到不同操作系统的时候,都可以考虑使用抽象工厂模式


4.模板方法模式:(汽车模型:模板类中run())

定义一个操作中的算法的框架,将一些步骤延迟到子类中;使得子类可以不改变一个算法的结构即可重定义该算法的某些特定的步骤


优点:封装不变部分,扩展可变部分;提取公共部分代码,便于维护

缺点:阅读代码困难


使用场景:多个子类有公有方法,且逻辑相同;核心算法设计为模板算法;重构时,把相同的代码抽取到父类

模板方法模式确实非常简单,仅仅使用了java的继承机制

模板方法加上final关键字,不允许被复写


通用代码如下:

1)抽象模板类

public  abstract class AbstracClass{

//基本方法

 protected abstract void doSomething();

//基本方法
      protected abstract void doAnything();

//模板方法

public void templateMethod(){
//调用基本方法,完成相关逻辑

this.doAnything();

this.doSomething();

}

}

2)具体模板类

public class ConcreteClass1 extends AbstractClass {
     //实现基本方法
     protected void doAnything() {
             //业务逻辑处理
     }
     protected void doSomething() {
             //业务逻辑处理
     }
}
public class ConcreteClass2 extends AbstractClass {     //实现基本方法
     protected void doAnything() {
             //业务逻辑处理
     }
     protected void doSomething() {
             //业务逻辑处理
     }
}

3)场景类

public class Client {
     public static void main(String[] args) {
             AbstractClass class1 = new ConcreteClass1();
             AbstractClass class2 = new ConcreteClass2();               
             //调用模板方法
             class1.templateMethod();
             class2.templateMethod();
     }
}


5.建造者模式:(汽车模型创建(run的顺序客户指定))

将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的显示

注:关注的是零件类型和装配顺序(与工厂模式最大不同点)


优点:封装性;建造者独立,便于扩展;便于控制细节风险


使用场景:相同的方法,不同的执行顺序,产生不同的结果时,可以采用建造者模式;多个部件,都可以装配到一个对象中,但产生的结果不同;产品类中调用顺序不同产生了不同


最佳实践:使用建造者模式时候考虑下模板方法模式


通用源码如下:

1)产品类(通常它是一个组合或继承实现的类)

public class Product{

public void doSomething(){
             //独立业务处理
     }

}

2)抽象建造者

public abstract class Builder{

//设置产品的不同部分,以获得不同的产品

public abstract void setPart();

//建造产品

public abstract Product buildProduct();

}

3)具体建造者(多个产品类就有多个具体建造者,而且多个类具有相同的接口或抽象类)

public class ConcreteBuilder extends Builder {
     private Product product = new Product();
     //设置产品零件     public void setPart(){
             /*
              * 产品类内的逻辑处理
              */
     }  
     //组建一个产品
     public Product buildProduct() {
             return product;
     }
}

4)导演类(导演类起到封装的作用,避免高层模块深入到建造者内部的实现类)

public class Director{

Private Builder builder = new ConcreteBuilder ();

public Product getAProduct(){

builder.setPart();

bulider.buildProduct();

}

}


6.代理模式(律师)

为其他对象提供一种代理以控制对这个对象的访问(代理与被代理对象实现同一个接口)


Struts2的form元素映射就是采用代理模式(动态代理)

通常情况下一个接口有一个代理类就可以了,在代理类的构造函数中传递被代理者

动态代理:在运行阶段才指定代理哪个对象

优点:职责清晰(真实角色不用关心其他非本职责的事务),高扩展性,


通用代码如下:

1)抽象主题类

public  Interface Subject{

public  void request();

}

2)真实主题类

public class RealSubject implements Subject {
     //实现方法
     public void request() {
             //业务逻辑处理
     }
}

3)代理类

public class Proxy implements Subject{

//要代理实现那个类

private Subject subject = null;

//默认被代理者

public Proxy(){

this.subject = new Proxy();

}

//通过构造函数传递代理者

public Proxy(Object...objects ){

}

//实现接口中定义的方法
     public void request() {
             this.before();
             this.subject.request();
             this.after();
     }
     //预处理
     private void before(){
             //do something
     }
     //善后处理
     private void after(){
             //do something
     }

}

动态代理:(被代理类必须实现一个接口)根据被代理的接口生成所有方法


Dynamic核心代码:
//寻找JoinPoint连接点,AOP框架使用元数据定义
             if(true){
                    //执行一个前置通知
                    (new BeforeAdvice()).exec();
             }
             //执行目标,并返回结果
             return (T)Proxy.newProxyInstance(loader,interfaces, h); MyInvocationHandler核心代码:
//被代理的对象
     private Object target = null;
     //通过构造函数传递一个对象
     public MyInvocationHandler(Object _obj){
             this.target = _obj;
     }
     //代理方法     
     public Object invoke(Object proxy, Method method, Object[] args)
                    throws Throwable {
             //执行被代理的方法
             return method.invoke(this.target, args);
     }
最佳实践:调试时,只要看到类似$Proxy()这样的机构,这是一个动态代理类


7.原型模式(电子账单系统的邮件发送(600万邮件))
不通过new关键字来产生一个对象,而是通过对象复制(对象实现cloneable接口)来实现

原型模式的核心就是一个clone方法

优点:性能优良:内存二进制流的拷贝,用在一个循环体内产生大量的对象时

逃避了构造函数的约束

原型模式一般很少单独出现,一般是和工厂方法模式一起出现,通过clone产生一个新对象,然后由工厂方法提供给调用者

浅拷贝:Object类提供的clone方法只拷贝本对象,其内部的数组、引用对象不拷贝,还是指向原生对象的内部元素的地址

注:使用原型模式时,引用的成员变量是类的成员变量,而且必须是一个可变的引用对象,而不是一个原型类型或不可变对象

8.中介者模式(进销存管理)

用一个中介对象封装一系列的对象交互,中介者使各对象不需要显示的相互作用,从而使其耦合松散

优点:减少类之间耦合

缺点:同事类越多,中介者的逻辑越复杂

使用场景:适用于对象之间紧密耦合的情况,紧密耦合的标准是在类图中出现蜘蛛网状结构

实际应用:

1)MVC框架,其中的C(Controller)就是一个中介者,叫做前端控制器(Front Controller),它的作用就是把M(Model,业务逻辑)和V(View,视图)隔离开

2)每个机场都会看到有一个“××机场调度中心”,它就是具体的中介者,用来调度每一架要降落和起飞的飞机

3)中介服务


9.命令模式(接头负责人(需求组、美工组、代码组)与客户交互;)

将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销与恢复

优点:类间解耦,可扩展性

命令模式可以结合责任链模式,实现命令族解析任务;结合模板方法模式,则可以减少Command子类的膨胀问题

缺点:命令类容易膨胀

使用场景:是命令的地方就可以使用命令模式

相关代码:

在每个命令类中通过构造函数定义了该命令针对哪个接受者发出的

public class ConcreteCommand extends Command {
     //哪个Receiver类进行命令处理
     private Receiver receiver;
     //构造函数传递接收者
     public ConcreteCommand2(Receiver _receiver){
             this.receiver = _receiver;
     }
     //必须实现一个命令
     public void execute() {
             //业务处理
             this.receiver.doSomething();
     }
}
public class Invoker {
     private Command command;
     //受气包,接受命令
     public void setCommand(Command _command){
             this.command = _command;
     }
     //执行命令
     public void action(){
             this.command.execute();
     }}


10.责任链模式(古代妇女出门逛街问题)

使多个对象有机会处理请求,从而避免了请求的发送者和接受者之间的耦合关系,将这些对象连成一条链,并沿着这个链传递请求,知道有对象处理它为止

优点:将请求与处理分开

缺点;性能问题

注意:链中节点数需要控制,在Handler中设置一个最大节点数

最佳实践:父类实现了请求传递的功能,子类实现请求的处理(ViP用户和普通用户注册)

相关代码:

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);
}


11.装饰模式(四年级的成绩单)

动态地给对象添加一些额外的职责。就增加功能来说装饰模式比子类更为灵活

装饰类是一个特殊的代理类;装饰类把动作委托给需要装饰的对象

优点:装饰类和被装饰类可以独立发展,而不会互相耦合,它是继承关系的一个替代方案

缺点::多层的装饰是比较复杂的。你想想看,就像剥洋葱一样,你剥到了最后才发现是最里层的装饰出现了问题

使用场景:扩展一个类的功能;动态的给一个对象增加功能,这些功能可以动态的撤销;需要为一批兄弟类进行改装或增加功能,首选装饰类模式

最贱实践:在一个项目中,你会有非常多的因素考虑不到,特别是业务的变更,不时地冒出一个需求,尤其是提出一个令项目大量延迟的需求时,装饰模式可以给我们很好的帮助,通过装饰模式重新封装一个类,而不是通过继承来完成


Decorator装饰角色
一般是一个抽象类,做什么用呢?实现接口或者抽象方法,它里面可不一定有抽象的方法呀,在它的属性里必然有一个private变量指向Component抽象构件ConcreteDecoratorA和ConcreteDecoratorB是两个具体的装饰类,你要把你最核心的、最原始的、最基本的东西装饰成其他东西


具体装饰类的代码:

public class ConcreteDecorator2 extends Decorator {
     //定义被修饰者
     public ConcreteDecorator2(Component _component){
             super(_component);
     }
     //定义自己的修饰方法
     private void method2(){
             System.out.println("method2修饰");
     }
     //重写父类的Operation方法
     public void operate(){
             super.operate();
             this.method2();
     }
}

注: 原始方法和装饰方法的执行顺序在具体的装饰类是固定的,可以通过方法重载实现多种执行顺序

场景类代码:

public class Client {
     public static void main(String[] args) {
             Component component = new ConcreteComponent();
             //第一次修饰
             component = new ConcreteDecorator1(component);
             //第二次修饰
             component = new ConcreteDecorator2(component);
             //修饰后运行
             component.operate();
     }
}




12.策略模式(刘备娶媳妇,诸葛亮锦囊妙计)
定义一组算法,将每个算法都封装起来,并且使他们之间可以互换

优点:算法可以自由切换,避免使用多重条件判断,扩展性良好

缺点:策略类复用的可能性很小,类数量增多;所有策略类都向外暴露(可以使用工厂方法模式、代理模式或亨元模式修正这个缺陷)

使用场景:多个类只有在算法或行为上稍有不同的场景;算法需要自由切换的场景;需要使用屏蔽算法的场景

注:如果系统中的一个策略家族的具体策略数量超过4个,则需要考虑使用混合模式


封装角色代码:
public class Context {
     //抽象策略
     private Strategy strategy = null;  
     //构造函数设置具体策略
     public Context(Strategy _strategy){
             this.strategy = _strategy;
     }
     //封装后的策略方法
     public void doAnythinig(){
             this.strategy.doSomething();
     }
}


13.适配器模式(电脑电源适配器)
将一个类的接口变换成客户所期待的另一种接口,从而从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作

优点: 适配器模式可以让两个没有任何关系的类在一起运行;类的透明性、复用度、 灵活性非常好

使用场景:修改一个已经投产中的接口时,适配器模式可能是最适合你的模式

注意事项:详细设计阶段不要考虑适配器模式,它的主要场景是扩展应用中


对象适配器和类适配器的区别是:类适配器是类间继承,对象适配器是对象的合成关
系,也可以说是类的关联关系


14.迭代器模式
提供一种方法访问一个容器对象中各个元素,而又不暴露该对象的内部细节

注:很少使用,除非是产品性质的开发

最佳实践:做Java开发,尽量不要自己写迭代器模式,是因为Java把迭代器模式已经融入到基本API中


15.组合模式(树形菜单)

将对象组合成树形结构以表示整体-部分的层次关系,是用户对单个对象和组合对象的使用一致性

优点:高层模块调用简单(一棵树形机构中的所有节点都是Component),节点自由增加

缺点:不能直接使用树叶和树枝

使用场景:维护和展示部分-整体关系的场景,如属性菜单、文件夹, 从一个整体中能够独立出部分模块或功能的场景

最佳实践:系统的Logo,下边分为两部分:左边是导航菜单,右边是展示区,左边的导航菜单一般都是树形的结构,比较清晰,有

非常多的JavaScript源码实现了类似的树形菜单



 树枝构件代码:
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.componentArrayList.remove(component);
     }
     //获得分支下的所有叶子构件和树枝构件
     public ArrayList<Component> getChildren(){
             return this.componentArrayList;
     }
}
 场景类代码:
public class Client {
     public static void main(String[] args) {
            //创建一个根节点
             Composite root = new Composite();
             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.doSomething();
                  }else{ //树枝节点
                          display((Composite)c);
                  }
             }
     }
}


16.观察者模式(李斯观察韩非子)
定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖它的对象都会得到通知并更新

优点:观察者和被观察者之间是抽象耦合,建立一套触发机制

缺点:效率问题

使用场景: 关联行为场景(关联行为是可拆分的);事件多级触发场景;跨系统的消息交换场景,如消息队列的处理机制使用观察

者模式也有以下两个重点问题要解决:

广播链的问题:,根据经验建议,在一个观察者模式中最多出现一个对象既是观察者也是被观察者

最佳实践:(ATM取钱)

 观察者和被观察者之间的消息沟通:在实际中一般的做法是:观察者中的update方法接受两个参数,一个是被观察者,一个是

DTO(Data Transfer Object,据传输对象),DTO一般是一个纯洁的JavaBean;

 观察者响应方式:一是采用多线程技术,甭管是被观察者启动线程还是观察者启动线程,都可以明显地提高系统性能;二是缓存技术


被观察者父类代码:
public abstract class Subject {
     //定义一个观察者数组
     private Vector<Observer> obsVector = new Vector<Observer>();
     //增加一个观察者
     public void addObserver(Observer o){
             this.obsVector.add(o);
     }
     //删除一个观察者
     public void delObserver(Observer o){
             this.obsVector.remove(o);
     }
     //通知所有观察者
     public void notifyObservers(){
             for(Observer o:this.obsVector){
                     o.update();
             }
     }
}
具体观察者类代码:
public class ConcreteObserver implements Observer {
     //实现更新方法
     public void update() {
             System.out.println("接收到信息,并进行处理!");


17.备忘录模式(男孩搭讪女孩实验(电影Next))
在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态,这样以后就可以将该对象恢复到原先保存的状态,通俗的说备忘录模式就是一个对象的备份模式,提供了一种程序数据的备份方法
注意事项:标准的备忘录模式很难在项目中遇到,基本上都有一些变换处理方式
使用场景:需要保存和恢复数据的相关状态场景; 提供一个可回滚(rollback)的操作; 数据库连接的事务管理


 发起人角色代码:
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(BeanUtils.backupProp(this));
     }
     //恢复一个备忘录
     public void restoreMemento(this, _memento.getStateMap()){
              BeanUtils.restoreProp(this, _memento.getStateMap());
     }
  //内置类
     private class Memento implements IMemento{
             //发起人的内部状态
             private String state = "";
             //构造函数传递参数
             private Memento(String _state){
                     this.state = _state;             }
             private String getState() {
                     return state;
             }
             private void setState(String state) {
                     this.state = state;
             }
     }
}
内置类Memento全部是private的访问权限,也就是说除了发起人外,别人休想访问到,
那如果要产生关联关系又应如何处理呢?通过接口!别忘记了我们还有一个空接口是公共的
访问权限
public interface IMemento {
}


备忘录管理者代码:
public class Caretaker {
     //备忘录对象
     private IMemento memento;
     public IMemento getMemento() {
             return memento;
     }
     public void setMemento(IMemento memento) {
             this.memento = memento;
     }
}


场景类
public class Client {
     public static void main(String[] args) {
             //定义出发起人
             Originator originator = new Originator();
             //定义出备忘录管理员
             Caretaker caretaker = new Caretaker();
             //创建一个备忘录
             caretaker.setMemento(originator.createMemento());
             //恢复一个备忘录
             originator.restoreMemento(caretaker.getMemento());
     }
}
在系统设计时,如果考虑对象的安全问题,则可以提供两个接口,一个是业务的正常接口,
实现必要的业务逻辑,叫做宽接口;另外一个接口是一个空接口,什么方法都没有,其目的
是提供给子系统外的模块访问,比如容器对象,这个叫做窄接口


18.访问者模式(要统计所有员工的工资(员工×1,经理×1.2)之和)
封装一些作用于某种数据结构中各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新操作

优点:符合单一职责原则(Employee抽象类的两个子类负责数据的加载,而Visitor类则负责报表的展现);扩展性高,灵活性好

缺点:具体元素对访问者公布细节;具体元素变更比较困难;违背了依赖倒置转原则(访问者依赖的是具体元素)

使用场景:业务规则要求遍历多个不同种类的对象;需要对一个对象结构中的对象进行很多不同并且不相关的操作;数据统计和报

表的批处理功能

注意事项:访问者模式是对迭代器模式的扩充,可以遍历不同的对象,然后执行不同的操作


最佳实践:使用于大规模重构的项目,通过访问者模式可以把一些功能进行梳理,打到最终目的--功能集中化(统一的报表运算)

 具体元素代码:
public class ConcreteElement1 extends Element{
     //完善业务逻辑
     public void doSomething(){
             //业务处理
     }
     //允许那个访问者访问
     public void accept(IVisitor visitor){
             visitor.visit(this);
     }
}
 具体访问者代码:
public class Visitor implements IVisitor {
     //访问el1元素
     public void visit(ConcreteElement1 el1) {
             el1.doSomething();
     }
     //访问el2元素
     public void visit(ConcreteElement2 el2) {
             el2.doSomething();
     }
}


19.状态模式(电梯的行为受电梯的状态约束)
当一个对象内在状态改变时允许改变其行为,这个对象看起来像改变了其类;状态模式的核心是封装,状态的变更引起了行为的变更

优点:结构清晰(避免switch和if else逻辑),体现了开闭原则和单一职责原则,封装性好

缺点:类膨胀

使用场景:行为随状态的变化而变化;条件、分支判断语句的替代者

最佳实践:工作流开发,通过状态机(State Machine)来管理

注意事项:行为受状态约束的情况下可以使用状态模式,使用时对象的状态最好不要超过5个

角色说明:
ConcreteState——具体状态角色

每一个具体状态必须完成两个职责:本状态的行为管理以及趋向状态处理,通俗地说,就是本状态下要做的事情,以及本状态如何过渡到其他状态
Context——环境角色

定义客户端需要的接口,并且负责具体状态的切换

环境角色有两个不成文的约束:

1)把状态对象声明为静态常量,有几个状态对象就声明几个静态常量。

2)环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式


 抽象环境角色代码:
public abstract class State {
     //定义一个环境角色,提供子类访问
     protected Context context;
     //设置环境角色
     public void setContext(Context _context){
             this.context = _context;
     }
     //行为1
     public abstract void handle1();
     //行为2
     public abstract 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.setContext(this);
     }
     //行为委托
     public void handle1(){
             this.CurrentState.handle1();
     }
     public void handle2(){
             this.CurrentState.handle2();
     }}


20.解释器模式
给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子
优点:扩展性好
缺点:类膨胀,递归调用,效率问题
使用场景:重复发生的问题(多个服务器的日志分析处理)
最佳实践:解释器模式在实际的系统开发中使用得非常少


21.亨元模式(报考信息提取考试地点和考试科目为外部状态对象)

使用共享对象可有效的支持大量的细粒度的对象

对象的信息分为两个部分:内部状态(intrinsic)与外部状态(extrinsic)

内部状态:是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变

外部状态:是对象得以依赖的一个标记,是随环境改变而改变的、不可以共享的状态

注意:尽量使用Java基本类型作为外部状态

优点:大大减少应用程序创建的对象,降低程序内存的占用

缺点:提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随内部状态改变而改变

使用场景: 系统中存在大量的相似对象; 细粒度的对象都具备较接近的外部状态,而且内部状态与环境无关; 需要缓冲池的场景


享元工厂代码:
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;     }
}


22.桥梁模式(山寨公司生产产品)
将抽象和实现解耦,使得两者可以独立变化,抽象角色引用实现角色,或者说抽象角色的部分实现是由实现角色完成的

优点:抽象与实现的分离(实现可以不受抽象的约束,不用再绑定到一个固定的抽象层次上),优秀的扩展能力,实现细节对客户透明

使用场景:不希望或不适合使用继承的场景;接口或抽象类不稳定的场景;重用性要求挺高的场景

注意事项:桥梁模式的意图还是对变化的封装,尽量把可能变化的因素封装到最细、最小的逻辑单元中,避免风险扩散。因此读者在进行系统设计时,

发现类的继承有N层时,可以考虑使用桥梁模式



 实现化角色代码:
public interface 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;
     }
}


三.模式大PK

1.创造类模式大PK

创造类模式包括单例模式、原型模式工厂模式、抽象工厂模式、建造者模式

工厂模式VS建造者模式:工厂模式注重的是整体对象的创建方法,而建造者模式注重的是部件的构造过程,旨在通过一步一步的精确构造创建出一个

复杂的对象工厂方法模式创建的产品一般都是单一性质的产品,建造者模式创建的产品一般都是复合产品,它由各个部件复合而成如果需要详细关注一

个产品部件的生产、安装步骤,则选择建造者模式,否则选择工厂方法模式


2.结构类模式大PK
结构类模式包括适配器模式、桥梁模式、组合模式、装饰模式、门面模式、亨元模式和代理模式

代理模式VS装饰模式:共同点是都具有相同的接口,不同点:代理模式着重对代理过程的控制,而装饰模式则对类的功能的加强或减弱

装饰模式VS适配器模式:相同点都是包装作用,都是通过委托方式实现其功能,不同点是装饰模式包装的是自己的兄弟类,隶属于同一个家族(相同

接口或父类),适配器模式则修改的是非血缘关系类,把一个非本家族的对象伪装成本家族的对象


3.行为类模式大PK

行为类模式包括责任链模式,命令模式、解释器模式、迭代器模式、中介者模式、备忘录模式、观测者模式、状态模式、策略模式、访问者模式

策略模式VS命令模式:策略的模式的意图是封装算法,让这些算法独立,并且可以相互切换,而命令模式则是对动作的解耦,把一个动作的执行分为

执行对象(接收者角色)和执行行为(命令橘色),两者相互独立

策略模式VS状态模式:相同点都是通过Context类封装一个具体的行为;策略模式封装的是不同的算法,算法之间没有交互,而状态模式封装的是不同

的状态,以达到状态切换,行为随之改变的目的;策略模式的Context只是一个委托作用,负责算法的替换,而状态模式的context不仅仅是委托,还有

登记状态的变化













  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值