美文网首页
不懂设计模式终究是下层

不懂设计模式终究是下层

作者: 像鸟一样飞 | 来源:发表于2017-09-22 13:20 被阅读31次
    sjms.jpg

    单例模式

    概念:确保一个类只有一个实例,而且自行实例化并向整个系统提供这个实例
    UML中带==下划线的属性==是静态的;
    如下特点:

    1. 构造方法私有
    2. 指向自己实例的私有静态引用
    3. 以自己实例为返回值的公有静态方法
      单例模式可详细分为两类, 饿单例模式,懒单例模式
    /**
     * 饿汉式单例模式,在类被加载的时候就实例化好了对象
     */
    public class SingleTon {
        public static SingleTon singleTon = new SingleTon();
    
        private SingleTon() {
        }
    
        public static SingleTon getSingleTon() {
            return singleTon;
        }
    }
    
    /**
     * 懒汉式单例模式,在调用实例化方法的时候才会创建它的实例
     */
    public class SingleTon {
        public static SingleTon singleTon;
    
        private SingleTon() {
        }
    
        public static synchronized SingleTon getSingleTon() {
            if (singleTon == null) {
                singleTon = new SingleTon();
            }
            return singleTon;
        }
    
    }
    

    单例模式的优点:

    1. 在内存中只有一个对象,节省内存空间
    2. 避免频繁的创建销毁对象,加快效率
    3. 避免对共享资源的多重占用
    4. 可以全局访问
      适用场景:
    5. 只能适用单例类提供的方法来获取单例对象,使用反射会创建新的对象
    6. 多线程使用单例模式时,要注意线程安全
    7. 不要做断开单例类对象与类中静态引用的危险操作。(╯°Д°)╯︵┻━┻

    在java中饿汉要优于懒汉,还要因为构造方法是私有的,所以不能被继承ε(┬┬﹏┬┬)3

    工厂方法模式

    概念:定义一个创建对象的接口,让子类决定实例化哪一个类,工厂方法模式使一个类的实例化延迟到了子类。

    interface IProduct {
        public void productMethod();
    }
    
    class Product implements IProduct {
    
        @Override
        public void productMethod() {
            System.out.println("产品");
        }
    }
    
    interface IFactory {
        public IProduct createProduct();
    }
    
    class Factory implements IFactory {
    
        @Override
        public IProduct createProduct() {
            return new Product();
        }
    }
    
    public class FactoryClient {
    
        public static void main(String[] arg) {
            IFactory factory = new Factory();
            IProduct product = factory.createProduct();
            product.productMethod();
        }
    
    }
    

    工厂模式根据抽象程度分为三种:简单工厂模式(静态工厂模式),工厂方法模式,抽象工厂模式。
    主要优点:

    1. 使代码结构清晰,有效的封装变化。在编程中有些产品的实例化是比较复杂的多变的,通过工厂模式,将产品的实例化过程封装起来,使用者不用管产品的实例化过程,只需要依赖工厂即可得到产品对象。
    2. 调用者屏蔽了具体的产品类,即使产品的实现发生了变化,调用只关心或者依赖产品的接口就好了,不会产生任何影响。
    3. 降低耦合度,产品的实例化通常是比较复杂的,需要依赖很多的类,而这些类对于调用者来说无需知道,工厂只是把最终的产品对象,交给调用者,产品所依赖的类都是不存在的ヾ(๑╹◡╹)ノ"

    通过工厂方法模式的类图可以看出,工厂模式有四个要素:

    1. 工厂接口,是工厂方法模式的核心,用于与调用者交互,用来提供产品。
    2. 工厂实现,决定如何实现产品,有多少种产品,就要有多少种工厂实现。
    3. 产品接口,所有产品都必须遵守产品接口所定义的规范,产品接口也是调用者最关心的,产品接口定义的好坏,决定了代码的稳定性,与工厂接口一样,可以用抽象类来代替,但是不能违反里氏替换原则ヽ(#`Д´)ノ┌┛〃
    4. 产品实现,决定了产品的在客户端的具体行为。

    适用场景:
    作为“创建类模式”,在任何需要生成复杂对象的地方,都可以使用工厂模式。
    如果创建一个类需要大量的依赖其他类,那么调用者就会产生很强的耦合度,这时候可以考虑使用工厂模式,来降低调用者与外界的耦合度。

    抽象工厂模式

    建造者模式

    定义:将一个复杂对象的构建与表示分离,使得同样的构建过程可以创建不同的表示。
    类型:创建类模式
    四个要素:

    1. 产品类,一般是一个创建过程较为复杂的对象,在实际编程中,产品类可以是一个抽象类,或多个抽象类及其实现子类组成;
    2. 抽象建造者,为了将具体的建造过程交于他的子类实现,更容易扩展,最少有两个方法,一个是建造产品,一个是返回产品。
    3. 建造者,实现抽象建造者的方法,组建产品,返回组建好的产品。
    4. 导演类,调用适当的建造者来组建产品,一般不与产品发生依赖,用于封装程序中易变的部分(メ`ロ´)/
    class Product {
        private String name;
        private String type;
    
        public void setName(String name) {
            this.name = name;
        }
    
        public void setType(String type) {
            this.type = type;
        }
    
        public void showProduct() {
            System.out.println("name = " + name);
            System.out.println("type = " + type);
        }
    }
    
    abstract class Builder {
        public abstract void setPart(String arg1, String arg2);
        public abstract Product getProduct();
    }
    
    class ConcreteBuilder extends Builder {
        private Product product = new Product();
    
        @Override
        public void setPart(String arg1, String arg2) {
            product.setName(arg1);
            product.setType(arg2);
        }
    
        @Override
        public Product getProduct() {
            return product;
        }
    }
    
    /**
     * 导演让你创建啥,你就创建啥ヾ(o・ω・)ノ
     */
    class Director {
        private Builder builder = new ConcreteBuilder();
    
        public Product getAProduct() {
            builder.setPart("保时捷", "卡宴");
            return builder.getProduct();
        }
    
        public Product getBProduct() {
            builder.setPart("凤凰牌", "自行车");
            return builder.getProduct();
        }
    }
    
    public class BuilderClient {
        public static void main(String[] args) {
            Director director = new Director();
            Product p1 = director.getAProduct();
            p1.showProduct();
            Product p2 = director.getBProduct();
            p2.showProduct();
        }
    
    }
    

    建造者模式的优点:

    1. 一般产品类和建造者类都是比价稳定的,因此,将主要逻辑,以及具体实现,这些易变的部分封装在了导演类中。
    2. 当有现需求时候,只要实现一个新的建造者类就可以不动之前经过测试的代码了,不会引入风险。
      建造者模式与工厂模式的区别:
      与工厂模式相比,建造模式一般用来创建更加复杂的对象, 因为更加复杂的对象创建过程,需要一个导演类将这个复杂的创建过程独立出来。也就是说工厂模式将所有的对象创建过程封装在工厂中,有工厂类想客户端提供最终的产品。而建造者模式中,建造者只提供产品的各个组件的建造,然后将具体的建造过程交给导演类,由导演类将各个组件的建造特定的规则组成产品,交给客户端。

    原型模式(Prototype)

    定义:用原型实例指定创建对象的种类,并通过拷贝这些原型创建新的对象。
    类型:创建类模式
    原型模式主要用于对象的复制,它的核心就是原型类prototype,prototype需要具备两个条件

    • 实现Cloneable接口,它的作用只有一个,就是通知虚拟机可以安全的在实现了此接口的类上使用clone方法。只有实现了这个接口的类才可以被clone。
    • 重写clone方法,将权限修饰符修改为public,

    模板方法模式(template)

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

    架构师将整个应用的大体逻辑,试用大量的接口或者抽象类讲真个系统串起来,然后根据实现的难度不同交给高级工程师,初级工程师,由他们来实现子类,完成开发。
    模板方法模式的结构:

    模板方法模式由一个抽象类和一组(n>=1)子类组成,抽象类中方法分为三种

    1. 抽象方法,父类只声明而不实现,定义好规范,然后由其子类去实现。
    2. 模板方法,由抽象类声明并加以实现,一般来说模板方法调用抽象方法来完成主要的逻辑功能,并且,模板方法大多数会定义成final类型,指明主要的逻辑在子类中无法被重写。
    3. 钩子方法,由抽象类声明并加以实现,但是子类可以去扩展,子类可以通过扩展钩子方法,来影响模板方法的逻辑。
    4. 抽象类的任务是搭建逻辑框架,通常由经验丰富的人,抽象类的好坏直接决定了程序是否稳定,
    5. 实现类用来实现细节,模板方法正式通过实现类中扩展的方法来完成逻辑,只要实现类中扩展方法通过了单元测试,在模板方法正确的前提下,一般整体不会出现太大的错误。

    适用场景:

    • 容易扩展,一般来说,抽象类中的模板方法是不易发生改变的部分,而抽象方法式容易发生改变的部分,因此通过增加实现类一般很容易实现功能的扩展,符合开闭原则。
    • 便于维护,对于模板方法模式来说,正是由于他们的主要逻辑相同,才使用模板方法。
    • 灵活,因为有钩子方法,因此子类的实现也可以影响父类的主要运行逻辑,但是却违反了里氏替换原则。
    • 多个子类拥有相同的方法,并且这些方法的逻辑相同的情况下可以使用模板方法模式,在程序的主框架相同,细节不同的情况下,比较适合使用这种模式。

    中介者模式

    定义:用一个中介者对象封装一些列的交互对象,中介者使个对象不需要显示的互相作用,从而降低耦合,而且可以独立的改变他们之间的交互。
    结构:中介者模式又称为调停者模式,氛围三部分

    1. 抽象中介者,定义好同事类对象到中介者对象的接口,用于各同事类之间的通讯,一般包括一个或者多个抽象的时间方法,并由子类去实现。
    2. 中介者实现类:从抽象中介者继承而来,实现抽象中介者中定义的事件方法。从一个同事类接收消息,然后通过消息影响其他同时类。
    3. 如果一个对象会影响其他的对象,同时也会被其他对象影响,那么这两个对象称为同事类。在类图中,同事类只有一个,这其实是现实的省略,在实际应用中,同事类一般由多个组成,他们之间相互影响,相互依赖。同事类越多,关系越复杂。并且,同事类也可以表现为继承了同一个抽象类的一组实现组成。在中介者模式中,同事类之间必须通过中介者才能进行消息传递。

    代理模式

    为其他对象提供一种代理以控制这个对象的访问。

    结构:

    1. Subject抽象主题角色,可以是抽象类也可以是一个接口,普通业务类型的定义,无特殊要求。
    2. RealSubject具体角色,被委托角色,业务逻辑具体执行者。
    3. Proxy代理角色,负责对真实角色的应用,把所有抽象主题的方法,委托给真是主题角色实现,并且在真实角色处理完毕前后座预处理和善后工作。

    模板代码:

    interface Subject {
        void request();
    }
    
    class RealSubject implements Subject {
        private String name;
    
        public RealSubject(String name) {
            this.name = name;
        }
    
        @Override
        public void request() {
            System.out.println("name = " + name);
        }
    }
    
    class Proxy implements Subject {
        private Subject subject = null;
    
        public Proxy(Subject subject) {
            this.subject = subject;
        }
    
        @Override
        public void request() {
            this.before();
            this.subject.request();
            this.after();
        }
    
        //预处理工作
        private void before() {
            System.out.println(System.currentTimeMillis() + "预处理工作");
        }
    
        //善后工作
        private void after() {
            System.out.println(System.currentTimeMillis() + "善后工作");
        }
    }
    
    public class ClientProxy {
        public static void main(String[] args) {
            Subject subject = new RealSubject("zhangsan");
            Subject proxy = new Proxy(subject);
            proxy.request();
        }
    }
    1506480477076预处理工作
    name = zhangsan
    1506480477076善后工作
    

    代理模式优点:

    1. 职责清晰,真是角色就是实现实际的业务逻辑,不用关心其他非本职事物,
    2. 高扩展性,具体主题角色可以随时改变,只要实现了接口,甭管怎么变化,都逃不出我的手心,代理类可以不改变的情况下使用。
    3. 智能化,︵╰(‵□′)╯︵┻━┻

    观察者模式

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

    observe
    在软件系统中通常会有这样的需求,如果一个对象的状态发生改变,某些与他先关的对象也要做出改变。

    结构:

    1. 被观察者,从类图中可以看到,类中有一个用来存放观察者对象的Vector的容器,(在多线程中Vector是线程安全的,而不是用list),这个集合是被观察者的核心,另外有三个方法,attach方法,向这个容器中添加观察者对象,detach方法,从容器中移除观察者对象,notify方法,依次调用观察对象的对应方法。这个角色可以是是接口,也可以是抽象类或者具体的类,因为很多情况是和其他模式一起使用。
    2. 观察者,观察者角色一般是一个接口,它只有一个update方法,在被观察者状态发生改变是,这个方法就会被触发调用。
    3. 具体的被观察者,使用这个角色是为了便于扩展,可以在此角色中定义具体的业务逻辑。
    4. 具体的观察者,定义被观察者状态发生改变时,回调的观察者对象具体处理的逻辑。
    /**
     * 被观察者
     */
    abstract class Observeable {
        private Vector<Observer> vector = new Vector();
    
        public void addObserve(Observer obs) {
            this.vector.add(obs);
        }
    
        public void removeObserve(Observer obs) {
            this.vector.remove(obs);
        }
    
        protected void notifyObserve() {
            for (Observer observer : vector) {
                observer.update();
            }
        }
    
        public abstract void doSomething();
    }
    
    /**
     * 被观察者实例
     */
    class ContractObserve extends Observeable {
    
        @Override
        public void doSomething() {
            System.out.println("被观察者事件发生");
            this.notifyObserve();
        }
    }
    
    interface Observer {
        void update();
    }
    
    /**
     * 实例观察者1
     */
    class ConcreteObserve1 implements Observer {
    
        @Override
        public void update() {
            System.out.println("观察者1收到信息,并进行处理");
        }
    }
    
    /**
     * 实例观察者2
     */
    class ConcreteObserve2 implements Observer {
    
        @Override
        public void update() {
            System.out.println("观察者2收到信息,并进行处理");
        }
    }
    
    public class ObserveClient {
    
        public static void main(String[] args) {
            //创建被观察者
            //这里真正new的都是实现子类
            Observeable obs = new ContractObserve();
            obs.addObserve(new ConcreteObserve1());
            obs.addObserve(new ConcreteObserve2());
            obs.doSomething();
        }
    }
    
    

    观察者模式的优点:
    观察者与被观察者之间是一种轻度的关联关系,并且是抽象耦合的,这样对于二者来说都比较容易扩展。观察者模式是一种常用的触发机制,它形成一条触发链,依次对各个观察者的方法进行处理,但同时由于是链式触发,所以当观察者较多的时候,性能是比较担忧的,

    责任链模式

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

    策略模式

    定义:定义一组算法,将每个算法都封装起来,并且使他们之间可以相互转换。
    策略模式是把算法封装到一系列的类中去,并且这些类实现相同的接口,相互之间可以相互替换。他与模板方法的区别在于,在模板方法模式中调用算法的主体在抽象的父类中,而在策略模式中,调用算法的主体则是在封装了Context的封装类中。

    结构:

    1. 封装类,也叫上下文,对策略进行二次封装,目的是避免高层模块对策略的直接调用。
    2. 抽象策略,通常情况下为一个接口,当各个类中出现重复的逻辑时候,使用抽象类来封装这部分代码,此时会看上去像是模板方法。
    3. 具体策略,具体策略通常由一组封装了算法的类来担任,这些类之间可以根据需要自由替换。

    策略模式的优点

    1. 策略类之间可以相互转换,由于策略类实现自统一个抽象,所以他们之间可以自由切换。
    2. 易于扩展,增加一个新的策略模式非常的简单,可以在不修改原有代码的基础上进行扩展。
    3. 避免使用多重条件,如果不使用策略模式,所有的算法需要用条件语句去进行连接,这样的做法非常不容易维护。
    4. 维护各个策略类给开发者带来额外的开销。
    5. 客户端必须要知道所有策略类的区别,然后决定用哪一个,但是有违背迪米特法则。
      ヽ(`Д´)ノ︵ ┻━┻

    适用场景:
    策略模式实际上就是面向对象中的继承和多态。

    1. 几个类的主要逻辑相同,只是部分逻辑和算法上有所区别的情况。
    2. 有相似的行为,或者算法,客户端需要动态的取决定使用哪一个,那么可以使用策略模式,将这些算法封装起来供客户端调用。
    3. 一般与工厂方法模式,模板方法模式混合使用情况较多。

    相关文章

      网友评论

          本文标题:不懂设计模式终究是下层

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