美文网首页
设计模式之禅读书笔记

设计模式之禅读书笔记

作者: 代码在码我 | 来源:发表于2020-02-19 00:17 被阅读0次

    一、六大设计原则

    • 单一职责原则
    • 里式替换原则
    • 依赖倒置原则
    • 接口隔离原则
    • 迪米特法则
    • 开闭原则

    1、单一职责原则

    应该有且仅有一个原因引起类的变更。

    2、里式替换原则

    只要父类能出现的地方,子类就可以出现,而且替换为子类也不会产生任何错误或异常,使用者可能根本就不需要知道是父类还是子类。但是,反过来就不行了,有子类出现的地方,父类未必就能适应。

    应尽量避免子类的“个性”。

    3、依赖倒置原则

    高层模块不应该依赖低层模块,两者都应该依赖其抽象;
    抽象不应该依赖细节;
    细节应该依赖抽象。

    模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的;
    接口或抽象类不依赖于实现类;
    实现类依赖接口或抽象类。

    面向接口编程。

    在Java中,只要定义变量就必然要有类型,一个变量可以有两种类型:表面类型实际类型,表面类型是在定义的时候赋予的类型,实际类型是对象的类型。

    4、接口隔离原则

    客户端不应该依赖它不需要的接口。
    类间的依赖关系应该建立在最小的接口上。

    5、迪米特法则

    一个对象应该对其他对象有最少的了解。

    在实际应用中经常会出现这样一个方法:放在本类中也可以,放在其他类中也没有错,那么,衡量原则:如果一个方法放在本类中,既不增加类间关系,也对本类不产生负面影响,那就放置在本类中。

    迪米特法则的核心观念就是类间解耦,弱耦合。

    6、开闭原则

    一个软件实体如类、模块和函数应该对扩展开放,对修改关闭。

    如何使用:
    1.抽象约束:第一,通过接口或抽象类约束扩展,对扩展进行边界限定,不允许出现在接口或抽象类中不存在的 public 方法;第二,参数类型、引用对象尽量使用接口或者抽象类,而不是实现类;第三,抽象层尽量保持稳定,一旦确定即不允许随便修改。
    2.元数据(metadata)控制模块行为
    3.制定项目章程
    4.封装变化

    元数据:用来描述环境和数据的数据,通俗地讲就是配置参数,参数可以从文件中获得,也可以从数据库中获得。

    二、单例模式

    1、饿汉模式

    public class Singleton {
        private static Singleton instance = new Singleton();
        private Singleton(){}
        public static Singleton getInstance(){
            return instance;
        }
    }
    

    2、懒汉模式(线程不安全)

    public class Singleton {
        private static Singleton instance;
        private Singleton(){}
        public static Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    3、懒汉模式(线程安全)

    public class Singleton{
        private static Singleton instance;
        private Singleton(){}
        public static synchronized Singleton getInstance(){
            if(instance == null){
                instance = new Singleton();
            }
            return instance;
        }
    }
    

    每次调用getInstance方法时都需要进行同步,造成不必要的同步开销,而且大部分时候我们是用不到同步的,所以不建议用这种模式。

    4、双重检查模式(DCL)

    public class Singleton{
        private volatile static Singleton instance;
        private Singleton(){}
        public static Singleton getInstance(){
            if(instance == null){
                synchronized(Singleton.class){
                    if(instance == null){
                        instance = new Singleton();
                    }
                }    
            }
            return instance;
        }
    }
    

    5、静态内部类单例模式

    public class Singleton{
        private Singleton(){}
        public static Singleton getInstance(){
            return SingletonHolder.sInstance;
        }
        private static class SingletonHolder{
            private static final Singleton sInstance = new Singleton();
        }
    }
    

    第一次加载Singleton类时并不会初始化sInstance,只有当第一次调用getInstance方法时虚拟机加载SingletonHolder并初始化sInstance,这样不仅能确保线程安全也能保证Singleton类的唯一性。

    6、枚举单例

    public enum Singleton{
        INSTANCE;
        public void doSomeThing(){}
    }
    

    7、利用容器实现单例模式

    public class SingletonManager{
        private static Map<String, Object> objMap = new HashMap<String, Object>();
        private Singleton(){}
        public static void registerService(String key, Object instance){
            if(!objMap.containsKey(key)){
                objMap.put(key, instance);
            }
        }
        public static Object getService(String key){
            return onjMap.get(key);
        }
    }
    

    三、工厂方法模式

    public abstract class Product{
        public void fun1(){
            // 产品类的公共方法
        }
        public abstract void fun2();
    }
    
    public class ConcreteProduct1 extends Product{
        @Override
        public void fun2(){
            //业务逻辑处理
        }
    }
    public class ConcreteProduct2 extends Product{
        @Override
        public void fun2(){
            //业务逻辑处理
        }
    }
    
    public abstract class Creator{
        /*
        * 创建一个产品对象,其输入参数类型可以自行设置
        */
        public abstract <T extends Product> T createProduct(Class<T> cls);
    }
    
    public class ConcreteCreator extends Creator{
        @Override
        public <T extends Product> T createProduct(Class<T> cls){
            Product product = null;
            try{
                product = (Product)Class.forName(c.getName()).newInstance();
            }catch(Exception e){
                //异常处理
            }
            return (T)product;
        }
    }
    
    Creator creator = new ConcreteCreator();
    Product product = creator.createProduct(ConcreteProduct1.class);
    

    扩展

    1、缩小为简单工厂模式

    public class HumanFactory{
        public static <T extends Human> T createHuman(Class<T> cls){
            Human human = null;
            try{
                human = (Human)Class.forName(cls.getName()).newInstance();
            }catch(Exception e){
                //捕获异常
            }
        }
    }
    

    HumanFactory类仅有两个地方发生变化:去掉继承抽象类,并在createHuman前增加static关键字。

    2、升级为多个工厂类

    public abstract class AbstractHumanFactory{
        public abstract Human createHuman();
    }
    

    3、替换单例模式

    public class Singleton{
        private Singleton(){}
        public void doSomething(){
            //业务处理
        }
    }
    
    public class SingletonFactory{
        private static Singleton singleton;
        static{
            try{
                Class cls = Class.forName(Singleton.class.getName());
                Constructor constructor = cls.getDeclaredConstructor();
                constructor.setAccessible(true);
                singleton = (Singleton)constructor.newInstance();
            }catch(Exception e){
                
            }
        }
        public static Singleton getSingleton(){
            return singleton;
        }
    }
    

    4、延迟初始化

    延迟初始化:一个对象被消费完成后,并不立刻释放,工厂类保持其初始状态,等待再次被使用。

    public class ProductFactory{
        private static final Map<String, Product> prMap = new HashMap<>();
        public static synchronized Product createProduct(String type) throws Exception{
            Product product = null;
            if(prMap.containsKey(type)){
                product = prMap.get(type);
            }else{
                if(type.equals("Product1")){
                    product = new ConcreteProduct1();
                }else{
                    ...
                }
                prMap.put(type, product);
            }
            return product;
        }
    }
    

    四、抽象工厂模式

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

    public abstract class AbstractProductA{
        public void shareMethod(){}
       
        public abstract void doSomething();
    }
    
    public class ProductA1 extends AbstractProductA{
        @Override
        public void doSomething(){
            //产品A1的实现方法
        }
    }
    
    public class ProductA2 extends AbstractProductA{
        @Override
        public void doSomething(){
            //产品A2的实现方法
        }
    }
    
    public abstract class AbstractCreator{
        public abstract AbstractProductA createProductA();
        public abstract AbstractProductB createProductB();
        //...
    }
    
    public class Creator1 extends AbstractCreator{
        @Override
        public AbstractProductA createProductA(){
            return new ProductA1();
        }
        @Override
        public AbstractProductB createProductB(){
            return new ProductB1();
        }
    }
    
    public class Creator2 extends AbstractCreator{
        @Override
        public AbstractProductA createProductA(){
            return new ProductA2();
        }
        @Override
        public AbstractProductB createProductB(){
            return new ProductB2();
        }
    }
    

    优点:封装性
    缺点:产品族扩展非常困难。

    五、模板方法模式

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

    为了防止恶意操作,一般,模板方法都加上final关键字,不允许被复写。

    public abstract class AbstractClass{
        protected abstract void doSomething();
        protected abstract void doAnything();
        public final void templateMethod(){
            this.doAnything();
            this.doSomething();
        }
    }
    
    public class ConcreteClass1 extends AbstractClass{
        @Overried
        protected void doAnything(){
            //业务逻辑处理
        }
        @Override
        protected void doSomething(){
            //业务逻辑处理
        }
    }
    public class ConcreteClass2 extends AbstractClass{
        @Overried
        protected void doAnything(){
            //业务逻辑处理
        }
        @Override
        protected void doSomething(){
            //业务逻辑处理
        }
    }
    

    注意,抽象模板中的基本方法尽量设计为protected类型,符合迪米特法则,不需要暴露的属性或方法尽量不要设置为protected类型。实现类若非必要,尽量不要扩大父类的访问权限。

    六、建造者模式

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

    角色:Product 产品类、Builder 抽象建造者、ConcreteBuilder 具体建造者、Director 导演类

    public class Product{
        public void doSomething(){
            //...
        }
    }
    
    public abstract class Builder{
        //设置产品的不同部分,以获得不同的产品
        public abstract void setPart();
        //建造产品
        public abstract Product buildProduct();
    }
    
    public class ConcreteProduct extends Builder{
        private Product product = new Product();
        @Override
        public void setPart(){
            //产品类内的逻辑处理
        }
        @Override
        public Product buildProduct(){
            return product;
        }
    }
    
    public class Director{
        private Builder builder = new ConcreteProduct();
        
        public Product getAProduct(){
            builder.setPart();
            return builder.buildProduct();
        }
    }
    

    如果有多个产品类就有几个具体的建造者。
    导演类起到封装的作用,避免高层模块深入到建造者内部的实现类。当然,在建造者模式比较庞大时,导演类可以有多个。

    建造者模式关注的是零件类型和装配工艺(顺序)。
    建造者模式最主要的功能是基本方法的调用顺序安排,也就是这些基本方法已经实现了,通俗地说就是零件的装配,顺序不同产生的对象也不同;而工厂方法则重点是创建,创建零件是它的主要职责,组装顺序不是它关心的。

    七、代理模式

    为其他对象提供一种代理以控制对这个对象的访问。
    也叫委托模式。

    public interface Subject{
        void request();
    }
    
    public class RealSubject implements Subject{
        @Override
        public void request(){
            //...
        }
    }
    
    public class Proxy implements Subject{
        //要代理哪个实现类
        private Subject subject = null;
        public Proxy(){
            this.subject = new Proxy();
        }
        public Proxy(Object... objects){
            //...
        }
        @Override
        public void request(){
            this.before();
            this.subject.request();
            this.after();
        }
        private void before(){
            //预处理...
        }
        private void after(){
            //善后处理...
        }
    }
    

    一个代理类可以代理多个被委托者或被代理者,因此一个代理类具体代理哪个真实主题角色,是由场景类决定的。

    public Proxy(Subject _subject){
        this.subject = _subject;
    }
    

    代理是有个性的,一个类可以实现多个接口,完成不同任务的整合。也就是说代理类不仅仅可以实现主题接口,也可以实现其他接口完成不同的任务,而且代理的目的是在目标对象方法的基础上作增强,这种增强的本质通常就是对目标对象的方法进行拦截和过滤。

    动态代理

    动态代理是在实现阶段不用关心代理谁,而是在运行阶段才指定代理哪一个对象。
    AOP (Aspect Oriented Programming)

    public class GamePlayIH implements InvocationHandler{
        Class cls = null;//被代理者
        Object obj = null;//被代理的实例
        public GamePlayIH(Object _obj){
            this.obj = _obj;
        }
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable{
            Object result = method.invoke(this.obj, args);
            return result;
        }
    }
    

    其中的invoke方法是InvocationHandler定义必须实现的,它完成对真实方法的调用。动态代理实现代理的职责,业务逻辑Subject实现相关的逻辑功能。

    public interface Subject{
        void doSomething(String str);
    }
    
    public class RealSubject implements Subject{
        @Override
        public void doSomething(String str){
            //...
        }
    }
    
    public class MyInvocationHandler implements InvocationHandler{
        private Object target = null;
        public MyInvocationHandler(Object _obj){
            this.target = _obj;
        }
        
        @Override
        public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
            //执行被代理的方法
            return method.invoke(this.target, args);
        } 
    }
    
    public class DynamicProxy<T>{
        public static <T> newProxyInstance(ClassLoader loader, Class<?> interfaces, InvocationHandler h){
            if(true){
                //执行一个前置通知(先前做一些什么的业务处理之类)
                (new BeforeAdvice()).exec();
            }
            return (T)Proxy.newProxyInstance(loader, interfaces, h);
        }
    }
    

    动态代理的主要意图是横切面编程,在不改变我们已有代码结构的情况下增强或控制对象的行为。

    八、原型模式

    用原型实例指定创建对象的种类,并且通过拷贝这些原型创建新的对象。
    clone方法。

    public class PrototypeClass implements Cloneable{
        @Override
        public ProrotypeClass clone(){
            PrototypeClass prototypeClass = null;
            try{
                prototypeClass = (PrototypeClass)super.clone();
            }catch(CloneNotSupportedException e){
                //..
            }
            return prototypeClass;
        }
    }
    

    这就是原型模式!

    注意事项

    1、构造函数不会被执行

    Object类的clone方法的原理是从内存中(具体地说就是堆内存)以二进制流的方式进行拷贝,重新分配一个内存块。

    2、浅拷贝和深拷贝

    public class Thing implements Cloneable{
        private List<String> arrayList = new ArrayList<>();
        @Override
        public Thing clone(){
            Thing thing = null;
            try{
                thing = (Thing)super.clone();
            }catch(CloneNotSuppoertedException e){
                e.printStackTrace();
            }
            return thing;
        }
        public void setValue(String value){
            this.arrayList.add(value);
        }
        public List<String> getValue(){
            return this.arrayList;
        }
    }
    
    Thing thing = new Thing();
    thing.setValue("张三");
    Thing cloneThing = thing.clone();
    cloneThing.setValue("李四"); //会改变原有thing里的列表
    

    Object类提供的方法clone只是拷贝本对象,其对象内部的数组、引用对象等都不拷贝,还是指向原生对象的内部元素地址,这种拷贝就叫做浅拷贝
    *String类型是没有clone方法的,处理机制也比较特殊,通过字符串池(stringpool)在需要的时候才在内存中创建新的字符串,在使用的时候就把String当做基本类型处理使用即可。

    public class Thing implements Cloneable{
        private List<String> arrayList = new ArrayList<>();
        @Override
        public Thing clone(){
            Thing thing = null;
            try{
                thing = (Thing)super.clone();
                thing.arrayList = (List<String>)this.arrayList.clone();//深拷贝
            }catch(CloneNotSuppoertedException e){
                e.printStackTrace();
            }
            return thing;
        }
    }
    

    九、中介者模式

    用一中介对象封装一系列的对象的交互,中介者使各对象不需要显示地相互作用,从而使其耦合松散,而且可以独立地改变它们之间的交互。

    大致类图:

    ConcreteMediator --> Mediator <-- Colleague

    十、命令模式

    命令模式是一个高内聚的模式,其定义:将一个请求封装成一个对象,从而让你使用不同的请求把客户端参数化,对请求排队或者记录请求日志,可以提供命令的撤销和恢复功能。

    public abstract class Receiver{
        public abstract void doSomething();
    }
    
    public class ConcreteReceiver1 extends Receiver{
        @Override
        public void doSomething(){
            //...
        }
    }
    
    public class ConcreteReceiver2 extends Receiver{
        @Override
        public void doSomething(){
            //...
        }
    }
    
    public abstract class Command{
        public abstract void execute();
    }
    
    public class ConcreteCommand1 extends Command{
        private Receiver receiver;
        public ConcreteCommand1(Receiver _receiver){
            this.receiver = _receiver;
        }
        @Override
        public void execute(){
            this.receiver.doSomething();
        }
    }
    
    public class ConcreteCommand2 extends Command{
        private Receiver receiver;
        public ConcreteCommand2(Receiver _receiver){
            this.receiver = _receiver;
        }
        @Override
        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();
        }
    }
    
    Invoker invoker = new Invoker();
    Receiver receiver = new ConcreteReceiver1();
    Command command = new ConcreteCommand1(receiver);
    invoker.setCommand(command);
    invoker.action();
    

    十一、责任链模式

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

    public abstract class Handler{
        private Handler newHandler;
        
        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);
    }
    

    抽象的处理者实现三个职责:一是定义一个请求的处理方法handlerMessage,唯一对外开放的方法;二是定义一个链的编排方法setNext,设置下一个矗立着5;三是定义了具体的请求者必须实现的两个方法:定义自己能够处理的级别getHandlerLevel和具体的处理任务echo

    public class ConcreteHandler1 extends Handler{
        @Override
        protected Response echo(Request request){
            return null;
        }
        @Override
        protected Level getHandlerLevel(){
            return null;
        }
    }
    
    public class ConcreteHandler2 extends Handler{
        @Override
        protected Response echo(Request request){
            return null;
        }
        @Override
        protected Level getHandlerLevel(){
            return null;
        }
    }
    
    public class Level{
        //定义一个请求和处理等级
    }
    public class Request{
        public Level getReuqestLevel(){
            return null;
        }
    }
    public class Response{
        //处理返回的数据
    }
    
    Handler handler1 = new ConcreteHandler1();
    Handler handler2 = new ConcreteHandler2();
    //...
    handler1.setNext(handler2);
    //...
    Response response = handler1.handlerMessage(new Request());
    

    十二、装饰模式

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

    public abstract class Component{
        public abstract void operate();
    }
    
    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 ConcreteDecorator extends Decorator{
        public ConcreteDecorator(Component _component){
            super(_component);
        }
        @Override
        public void operate(){
            this.method();
            super.operate();
        }
        private void method(){
            //装饰..
        }
    }
    

    十三、策略模式

    定义一组算法,将每个算法都封装起来,并且使他们之间可以互换。

    public interface Strategy{
        void doSomething();
    }
    
    public class ConcreteStrategy1 implements Strategy{
        @Override
        public void doSomething(){
            //具体策略
        }
    }
    public class ConcreteStrategy2 implements Strategy{
        @Override
        public void doSomething(){
            //具体策略
        }
    }
    

    策略模式的重点就是封装角色,他是借用了代理模式的思路,与代理模式的 差别就是策略模式的封装角色和被封装的策略类不是同一个接口,如果是同一个接口那就成为了代理模式

    public class Context{
        private Strategy strategy = null;
        public Context(Strategy _strategy){
            this.strategy = _strategy;
        }
        public void doAnything(){
            this.strategy.doSomething();
        }
    }
    
    Strategy strategy = new ConcreteStrategy1();
    Context context = new Context(strategy);
    context.doAnything();
    

    缺点:策略类数量增多,所有策略类都需要对外暴露。
    如果系统中一个策略家族的具体策略数量超过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);
    }
    

    每一枚举项都是public static final的,扩展性受到了一定的约束,因此在系统开发中,策略枚举一般担当不经常发生变化的角色。

    十四、适配器模式

    将一个类的接口变换成客户端所期待的另一种接口,从而使原本因接口不匹配而无法在一起工作的两个类能够在一起工作。

    public interface Target{
        void request();
    }
    
    public class ConcreteTarget implements Target{
        @Override
        public void request(){
            //..目标角色的实现
        }
    }
    
    public class Adaptee{
        public void doSomething(){
            //..原有业务逻辑
        }
    }
    
    public class Adapter extends Adaptee implements Target{
        @Override
        public void request(){
            super.doSomething();
        }
    }
    
    Target target = new ConcreteTarget();
    target.request();
    Target target2 = new Adapter();
    target2.request();
    

    当你有动机修改一个已经投产中的接口时,适配器模式可能是最适合你的模式。

    多个接口实现,把原有的继承关系变更为关联关系就可以了。

    十五、迭代器模式

    提供一种方法访问一个容器对象中各个元素,而又不需暴露该对象的内部细节。

    public interface Iterator{
        Object next();
        boolean hasNext();
        boolean remove();
    }
    
    public class ConcreteIterator implements Iterator{
        private Vector vector = new Vector();
        public int cursor = 0;
        
        public ConcreteIterator(Vector _vector){
            this.vector = _vector;
        }
        @Override
        public boolean hasNext(){
            return this.cursor != this.vector.size();
        }
        @Override
        public Object next(){
            if(this.hasNext()){
                return this.vector.get(this.cursor++);
            }
            return null;
        }
        @Override
        public boolean remove(){
            this.vector.remove(this.cursor);
            return true;
        }
    }
    
    public interface Aggregate{
        void add(Object object);
        void remove(Object object);
        public Iterator iterator();
    }
    
    public class ConcreteAggregate implements Aggregate{
        private Vector vector = new Vector();
        @Override
        public void add(Object object){
            this.vector.add(object);
        }
        @Override
        public Iterator iterator(){
            return new ConcreteIterator(this.vector);
        }
        @Override
        public void remove(Object object){
            this.remove(object);
        }
    }
    
    Aggregate agg = new ConcreteAggregate();
    agg.add("a");
    agg.add("b");
    agg.add("c");
    Iterator iterator = agg.iterator();
    while(iterator.hasNext()){
        //遍历
    }
    

    使用 Java 提供的 Iterator 一般就能满足你的要求的了。

    十六、组合模式

    将对象组合成树形结构以表示“部分-整体”的层次结构,使得用户对单个和组合对象的使用具有一致性。

    pulic abstract class Component{
        public void doSomething(){
            //..
        }
    }
    
    //树枝构件
    public class Composite extends Component{
        private List<Component> componentList = new ArrayList<>();
        public void add(Component component){
            this.componentList.add(component);
        }
        public void remove(Component component){
            this.componentList.remove(component);
        }
        public List<Component> getChildren(){
            return this.componentList;
        }
    }
    
    //树叶构件
    public class Leaf extends Component{
        //..
    }
    
    Composite root = new Composite();
    root.doSomething();
    Composite branch = new Composite();
    Leaf leaf = new Leaf();
    root.add(branch);
    branch.add(leaf);
    

    十七、观察者模式

    定义对象间一种一对多的依赖关系,使得每当一个对象改变状态,则所有依赖于它的对象都会得到通知并被自动更新。

    java.util.OBservable

    十八、门面模式

    要求一个子系统的外部与其内部的通信必须通过一个统一的对象进行。门面模式提供一个高层次的接口,使得子系统更易于使用。

    public class ClassA {
        public void doSomethingA(){
            //..
        }
    }
    public class ClassB {
        public void doSomethingB(){
            //..
        }
    }
    public class ClassC {
        public void doSomethingC(){
            //..
        }
    }
    
    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.b.doSomethingB();
        }
        public void methodC(){
            this.c.doSomethingC();
        }
    }
    

    不符合开闭原则,对修改关闭,对扩展开放。
    可以有多个门面、

    十九、备忘录模式

    在不破坏封装性的前提下,捕获一个对象的内部状态,并在该对象之外保存这个状态。这样以后就可将该对象恢复到先前保存的状态。 (后期语言的发展可以忽略这个之外的限制)

    //发起人角色
    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{
        pirvate 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 this.memento;
        }
        public void setMemento(Memento memento){
            this.memento = memento;
        }
    }
    
    Originator originator = new Originator();
    Caretaker caretaker = new Caretaker();
    caretaker.setMemento(originator.createMemento());
    originator.restoreMemento(caretaker.getMemento());
    

    备忘录模式的扩展

    1、clone 方式的备忘录

    public class Originator implements Cloneable{
        private Originator backup;
        //内部状态
        private Strng state = "";
        public String getState(){
            return state;
        }
        public void setState(String state){
            this.state = state;
        }
        public void createMemento(){
            this.backup = this.clone();
        }
        public void restoreMemento(){
            this.setState(this.backup.getState());
        }
        @Override
        protected Originator clone(){
            try{
                return (Originator)super.clone();
            }catch(CloneNotSupportedException e){
                e.printStackTrace();
            }
            return null;
        }
    }
    

    2、多状态的备忘录模式

    全状态备份方案:clone、数据技术等。
    继续扩展备忘录模式。HashMap 维护状态信息。

    二十、访问者模式

    封装一些作用于某些数据结构中的各元素的操作,它可以在不改变数据结构的前提下定义作用于这些元素的新的操作。

    public abstract class Element{
        //定义业务逻辑
        public abstract void doSomething();
        //允许谁来访问
        public abstract void accept(IVisitor visitor);  
    }
    
    public class ConcreteElement1 extends Element{
        @Override
        public void doSomething(){
            //..
        }
        @Override
        public void accept(IVisitor visitor){
            visitor.visit(this);
        }
    }
    public class ConcreteElement2 extends Element{
        @Override
        public void doSomething(){
            //..
        }
        @Override
        public void accept(IVisitor visitor){
            visitor.visit(this);
        }
    }
    
    public interface IVisitor{
        void visit(ConcreteElement1 el1);
        void visit(ConcreteElement2 el2);
    }
    
    public class Visitor implements IVisitor{
        @Override
        public void visit(ConcreteElement1 el1){
            el1.doSomething();
        }
        @Override
        public void visit(ConcreteElement2 el1){
            el2.doSomething();
        }
    }
    
    //结构对象
    public class ObjectStruture{
        public static Element createElement(){
            Random rand = new Random();
            if(rand.nextInt(100) > 50){
                return new ConcreteElement1();
            }else{
                return new ConcreteElement2();
            }
        }
    }
    
    for(int i=0; i<10; i++){
        Element e1 = ObjectStruture.createElement();
        e1.accept(new Visitor());
    }
    

    二十一、状态模式

    当一个对象内在状态改变时允许其改变行为,这个对象看起来像改变了其类。

    public abstract class State{
        protected Context context;
        public void setContext(Context _context){
            this.context = _context;
        }
        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.STATE1);
            super.context.handle1();
        }
    }
    
    public class ConcreteState2 extends State{
        @Override
        public void handle1(){
            super.context.setCurrentState(Context.STATE2);
            super.context.handle2();
        }
        @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.setContext(this);
        }
        //行为委托
        public void handle1(){
            this.currentState.handle1();
        }
        public void handle2(){
            this.currentState.handle2();
        }
    }
    

    环境角色有两个不成文的约束:
    把状态对象声明为静态变量,有几个状态对象就声明几个静态变量;
    环境角色具有状态抽象角色定义的所有行为,具体执行使用委托方式。

    Context context = new Context();//定义环境角色
    cotext.setCurrentState(new ConcreteState1());//初始化状态
    //行为执行
    context.handle1();
    context.handle2();
    

    隐藏了状态的变化的过程,它的切换引起了行为的变化,对外来说,只看到了行为发生改变,而不知道是状态变化引起的。

    状态间的自由切换可能会有多种,就需要把已有的集中状态按照一定的顺序再重新组装一下。(建造模式+状态模式)

    二十二、解释器模式

    给定一门语言,定义它的文法的一种表示,并定义一个解释器,该解释器使用该表示来解释语言中的句子。

    public abstract class Expression{
        public abstract Object interpreter(Context ctx);
    }
    
    //终结符表达式
    public class TerminalExpression extends Expression{
        @Override
        public Object interpreter(Context ctx){
            return null;
        }
    }
    
    //非终结符表达式
    public class NonterminalExpression extends Expression{
        public NoterminalExpression(Expression... expression){
            //..
        }
        @Override Object interpreter(Context ctx){
            //进行文法处理
            return null;
        }
    }
    

    每个非终结符表达式都代表了一个文法规则,并且每个文法规则都只关心自己周边的文法规则的结果(注意是结果),因此这就产生了每个非终结符表达式调用自己周边的非终结符表达式,然后最终、最小的文法规则就是终结符表达式,终结符表达式的概念就是如此,不能够再参与比自己更小的文法运算了。

    Context ctx = new Context();
    Stack<Expression> stack = null;
    for(;;){
        //进行语法判断,并产生递归调用
    }
    //产生一个完整的语法树,由各个具体的语法分析进行解析
    Expression exp = stack.pop();
    //具体元素进入场景
    exp.interpreter(ctx);
    

    使用场景:1.重复发生的问题可以使用解释器模式;2.一个简单的语法需要解释的场景。

    二十三、享元模式

    享元模式是池技术的重要实现方式。使用共享对象可有效地支持大量的细粒度的对象。

    细粒度对象和共享对象;
    内部状态与外部状态。内部状态是对象可共享出来的信息,存储在享元对象内部并且不会随环境改变而改变;外部状态是对象得以依赖的一个标记,是随环境改变而改变的、不可共享的状态。

    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(String _extrinsic){
            super(_extrinsic);
        }
        @Override
        public void operate(){
            //业务逻辑
        }
    }
    public class ConcreteFlyWeight2 extends FlyWeight{
        public ConcreteFlyWeight2(String _extrinsic){
            super(_extrinsic);
        }
        @Override
        public void operate(){
            //业务逻辑
        }
    }
    

    抽象享元中对外部状态加上了final关键字,避免被无意修改。

    public class FlyWeightFactory{
        private static Map<String,FlyWeight> pool = new HashMap<String,FlyWeight>();
        public static FlyWeight getFlyWeight(String extrinsic){
            FlyWeight flyWeight = null;
            if(pool.containsKey(extrinsic)){
                flyWeight = poo;.get(extrinsic);
            }else{
                flyWeight = new ConcreteFlyWeight(extrinsic);
                pool.put(extrinsic, flyWeight);
            }
            return flyWeight;
        }
    }
    

    优缺点:大大减少应用程序创建的对象;但提高了系统复杂性,需要分离出外部状态和内部状态,而且外部状态具有固化特性,不应该随内部状态改变而改变,否则导致系统的逻辑混乱。

    使用场景:系统中存在大量的相似对象;细粒度的对象都具备接近的外部状态,而且内部状态与环境无关,也就是说对象没有特定身份;需要缓冲池的场景。

    线程不安全问题:使用享元模式时,对象池中的享元对象尽量多,多到足够满足业务为止。
    性能平衡:尽量使用 Java 基本类型作为外部状态。

    二十四、桥梁模式

    将抽象和实现解耦,使得两者可以独立地变化。

    //实现化角色
    public interface Implementor{
        //基本方法
        void doSomething();
        void doAnything();
    }
    
    //具体实现化角色
    public class ConcreteImplementor1 implements Implementor{
        @Override
        public void doSomething(){
            //...
        }
        @Override
        public void doAnything(){
            //...
        }
    }
    public class ConcreteImplementor2 implements Implementor{
        @Override
        public void doSomething(){
            //...
        }
        @Override
        public void doAnything(){
            //...
        }
    }
    
    //抽象化角色
    public abstract class Abstracation{
        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();
        }
    }
    
    Implementor imp = new ConcreteImplementor1();
    Abstraction abs = new RefinedAbstraction(imp);
    abs.request();
    

    优点:抽象和实现分离;优秀的扩充能力;实现细节对客户透明

    使用场景:不希望或不适用使用继承的场景,如继承层次过度、无法更细化设计粒度等场景;接口或抽象类不稳定的场景;重用性要求较高的场景。

    相关文章

      网友评论

          本文标题:设计模式之禅读书笔记

          本文链接:https://www.haomeiwen.com/subject/otrofhtx.html