美文网首页面试JAVA
2018-09-16 JAVA设计模式

2018-09-16 JAVA设计模式

作者: 闭门造折 | 来源:发表于2018-09-19 17:39 被阅读11次

    主要参考资料:《Java开发中的23种设计模式详解》

    一、三大分类

    详细的分类模式可能不太好记,建议先知道三种分类,然后跳过这块继续阅读。

    1. 创建型模式:主要用于处理对象的创建,实例化对象。
      主要有:工厂模式、单例模式、建造者模式、原型模式
    2. 结构型模式:处理类和对象间组合。
      主要有:适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模式、享元模式
    3. 行为型模式:描述类和对象怎么交互或分工。
      主要有:策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式

    参考资料:《设计模式——怎么就给分成三类了呢?》

    二、六大原则

    1. 开闭原则

    对扩展开放,对修改关闭。即想实现新功能的时候,提供接口,但是不能对源代码做修改。

    2. 里氏代换原则

    一种规范,任何基类可以出现的地方,子类一定可以出现。这样才能确保衍生类替换基类的时候,不会出错。

    3. 依赖倒转原则

    针对接口编程,依赖于抽象,而不依赖具体

    4. 接口隔离原则

    参考资料《Java开发中的23种设计模式详解》中写,这个原则就是使用多个隔离的接口,比使用单一接口要好。但是我不理解什么是隔离的接口。
    继续查资料,参考资料《六大设计原则之接口隔离原则》有另两种解释:
    4.1 客户端不应该依赖他不需要的接口
    4.2 类间依赖关系应该建立在最小的接口上
    合起来就是减少臃肿庞大的接口,接口细化

    5. 迪米特法则(最少知道原则)

    一个实体应当尽量少的与其他实体发生相互作用,使得系统功能模块相对独立。

    6. 合成复用原则

    更多的使用合成/聚合的方式,而不是继承。

    三、具体模式

    以下为创建型模式

    1. 普通工厂模式

    定义创建对象的接口,实例化的时候,通过传入内容,实例化不同类。

    接口:
    public interface Sender(){
        void Send();
    }
    
    实现类1(邮件发送):
    public class MailSender implements Sender(){
        @Override
        public void Send(){
            System.out.println("this is mail sender");
        }
    }
    实现类2(邮包发送):
    public class BoxSender implements Sender(){
        @Override
        public void Send(){
            System.out.println("this is box sender");
        }
    }
    
    工厂类:
    public class SendFactory{
        public Sender produce(String type){
            if("mail".equals(type)){
                return new MailSender();
            }
            else if("box".equals(type)){
                return new BoxSender();
            }
            else{
                System.out.println("类型错误");
                return null;
            }
        }
    }
    
    2. 多个工厂方法模式

    实际上就是将上个模式中的工厂类中的判别,改为不同的方法,实例化的时候调用不同方法,创建不同实例化对象。

    public class SendFactory{
        public Sender produceMail(){
            return new MailSender();
        }
    
        public Sender produceBox(){
            return new BoxSender();
        }
    }
    
    3. 静态工厂方法模式

    在多个工厂方法模式的基础上,把工厂类中所有的子创建方法,改为static,也即是不需要特意创建工厂类的实例化对象,可以直接调用得到创建方法。

    4. 抽象工厂类

    为了可扩展性,拆分工厂类

    工厂类接口
    public interface Provider{
        public Sender produce();
    }
    第一个工厂类
    public class SendMailFactory implements Provider(){
        @Override
        public Sender produce(){
            return new MailSender();
        }
    }
    第二个工厂类
    public class SendBoxFactory implements Provider(){
        @Override
        public Sender produce(){
            return new BoxSender();
        }
    }
    main函数:
    public static main(String[] args){
        Provider provider = new SendMailFactory();
        //实例化工厂类对象
        Sender sender = provider,produce();
        //得到实例化对象产生的Sender对象
        sender.Send();
    }
    
    5. 单例模式

    计划生育,让一个类仅拥有一个实例化对象

    public class Singleton{
        private static Singleton intance = null;
        
        private Singleton(){
        }
        
        public static Singleton getInstance(){
            if(interface == null){
                //为空则实例化
                instance = new Singleton();
            }
            return instance;
        }
    
        public Object readResolve(){
            return instance;
        }
    }
    
    6. 建造者模式

    创建复合对象,其实建造者模式就是将抽象工厂模式利用起来。
    工厂模式是为了创建好单个对象
    建造者模式则是为了创建复合对象

    建造者类:
    public class Builder{
        private List<Sender> list = new ArrayList <Sender>();
        //一个类内公有的私有对象
        public void produceMailSender(int count){
            for(int i = 0; i < count; i++){
                list.add(new MailSender());
            }
        }
        public void produceBoxSender(int count){
            for(int i = 0; i < count; i++){
                list.add(new BoxSender());
            }
        }
    }
    调用的时候交替调用两个方法,即可得到一个重复交替的list队列
    
    7. 原型模式

    利用原型,来克隆产生新的对象

    public class Prototype implements Cloneable{
        public Object clone throws CloneNotSupportedException{
            //浅复制
            Prototype proto = (Prototype) super.clone();
            return proto;
        }
        public Object deepClone() throws IOException, ClassNotFoundException{
            //深复制
            //写入当前对象二进制流
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream oos = new ObjectOutputStream(bos);
            //向bos中写入this的内容
            oos.writeObject(this);
    
            //读出当前对象二进制流
            ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
            ObjectInputStream ois = new ObjectInputStream(bis);
    
            return ois.readObject();
        }
    }
    

    以下为结构型模式

    8. 类的适配器模式

    想把一个类,转换成满足一个新接口的类时,可以用类的适配器模式,创建一个新类,继承原来的类,并实现新的接口。

    原有的类:
    public class Source{
        public void method_old(){
            System.out.println("this is an old method");
        }
    }
    新的接口:
    public interface TargetInterface{
        public void method_old();
        public void method_new();
    }
    通过新的类实现:
    public class Adapter extends Source implements TargetInterface{
        @Override
        public void method_new(){
            System.out.println("this is a new method");
        }
    }
    
    9. 对象的适配器模式

    不再继承原有类,而是改为存储原有类实例化对象。

    新的类:
    public class Adapter implements TargetInterface{
        private Source source;
      
        public Adapter(Source source){
            super();
            this.source = source;
        }
    
        @Override
        public void method_new(){
            //新方法仍需要手动实现
            System.out.println("this is a new method");
        }
    
        @Override
        public void method_old(){
            source.method_old();
        }
    }
    
    10. 接口的适配器模式

    interface里面要求的方法太多了,但是不是所有的方法都是我们所需要的。使用抽象类实现所有接口,这样我们的具体类实现的时候,可以调用抽象类,并只实现其中部分接口就行了。

    原有的interface:
    public interface Sourceable{
        public void garbage_method1();
        public void garbage_method2();
        public void method3();
        public void method4();
    }
    通过抽象类,假装“实现”四种方法
    public abstract class Wrapper implements Sourceable{
        public void garbage_method1(){}
        public void garbage_method2(){}
        public void method3(){}
        public void method4(){}
    }
    当我们真的需要实现某个类的时候,只需要实现想实现的方法,并继承抽象类就行了
    public class Source extends Wrapper{
        public void method3(){
            System.out.println("the useful method");
        }
    }
    
    11. 装饰模式

    给一个对象增加一些新的功能

    接口需求
    public interface Sourceable{
        public void method();
    }
    原有类
    public class Source implements Sourceable{
        @Override
        public void method(){
            System.out.println("the original method!");
        }
    }
    装饰类
    public class Decorator implements Sourceable{
        private Sourceable source;
    
        public Decorator(Sourable source){
            super();
            this.source = source;
        }
        @Override
        public void method(){
            "do something there"
            source.method();
            "do something there"
        }
    }
    
    12. 代理模式

    和装饰模式非常像,唯一的差别是,装饰模式中,source是传入的参数。而代理模式中,source是new出来的对象。即代理模式中,不需要提前创建好要改进的类,直接调用代理模式的类即可。

    public Proxy(){
        super();
        this.source = new Source();
    }
    
    13. 外观模式

    多个类,不想让他们产生交流和关系。通过一个类统一调度,降低类类之间耦合度。

    三个不想让他们产生关联的类CPU Memory和Disk
    public class CPU{
        public void startup(){
            System.out.println("cpu start up!");
        }
        public void shutdown(){
            System.out.println("cpu shut down!");
        }
    }
    public class Memory{
        public void startup(){
            System.out.println("memory start up!");
        }
        public void shutdown(){
            System.out.println("memory shut down!");
        }
    }
    public class Disk{
        public void startup(){
            System.out.println("disk start up");
        }
        public void shutdown(){
            System.out.println("disk shut down");
        }
    }
    用外观模式,做一个统一调度类
    public class Computer{
        private CPU cpu;
        private Memory memory;
        private Disk disk;
    
        public Computer(){
            cpu = new CPU();
            memory = new Memory();
            disk = new Disk();
        }
    
        public startup(){
            cpu.startup();
            memory.startup();
            disk.startup();
        }
    }
    
    14. 桥接模式

    不想直接通过实例化对象.方法()的方式调用。
    不知道有什么用处,下方的例子中,先后实例化Source1和Source2,传入MyBridge中调用method方法,输出两个提示信息。

    接口设置
    public interface Sourceable{
        public void method();
    }
    两个实现类
    public class Source1 implements Sourceable{
        @Override
        public void method(){
            System.out.println("随便打点什么反正也不会运行我是第一个实现类");
        }
    }
    public class Source2 implements Sourceable{
        @Override
        public void method(){
            System.out.println("我是第二个实现类");
        }
    }
    定义一个虚类,来持有一个Source对象
    public abstract class Bridge{
        private Sourceable source;
        
        public void setSource(Sourceable source){
            this.source = source;
        }
        public Sourceable getSource(){
            return this.source;
        }
    }
    定义一个具体实现的类,继承虚类,不然不能实例化
    public class MyBridge() extends Bridge{
        public void method(){
            getSource().method();
        }
    }
    
    15. 组合模式

    通常用来表示树等结构
    举例:类中含有属性:子节点列表,父节点,权值,节点命名等

    16. 享元模式

    通常与工厂模式组合使用。如果某对象已存在,直接返回该对象,否则,新建一个对象。

    以下为行为型模式

    17. 策略模式

    定义一系列算法,可以互相替换。可以定义一个接口类,规定要实现的统一方法。
    策略模式通常使用于算法决策系统,用户只需要选择使用哪个算法即可。

    接口
    public interface Rule{
        public void calcu();
    }
    三个实现类
    public class Plus implements Rule{
        @Override
        public void calcu(){
            System.out.println("+");
        }
    }
    public class Sub implements Rule{
        @Override
        public void calcu(){
            System.out.println("-");
        }
    }
    public class Mul implements Rule{
        @Override
        public void calcu(){
            System.out.println("*");
        }
    }
    
    18. 模板方法模式

    定义一个抽象类,子类继承抽象类。实例化的时候采用
    抽象类类名 tmp = new 子类名();
    的方法调用。感觉是为了加深子类调用的理解。

    19. 观察者模式

    当一个类发生变化的时候,其他依赖该对象的对象会受到通知。就像是我关注了你,你发了个段子,我立刻就会收到消息。

    随意的接口
    public interface Observer{
        public void update();
    }
    两个实现类
    public class Observer1 implements Observer{
        public void update(){
            System.out.println("骗你的,其实根本不更新");
        }
    }
    public class Observer2 implements Observer{
        public void update(){
            System.out.println("我也是骗你的");
        }
    }
    监控器虚类
    public abstract class AbstractSubject{
        private Vector<Observer> vector = new Vector<Observer>();
        public void add(Observer observer){
            vector.add(observer);
        }
        public void del(Observer observer){
            vector.remove(observer);
        }
        修改预警:
        public void notifyObserver(){
            Enumeration<Observer> enumo = vector.elements();
        while(enumo.hasMoreElements()){
            enumo.nextElement().update();
        }
        }
    }
    
    20. 迭代器模式

    用类来实现迭代器的功能

    21. 责任链模式

    用类来实现链表的功能

    22. 命令模式

    实现命令发出者和执行者之间的解耦。实现请求和执行分开。
    指令(interface) - 指令调度器(实现指令功能,持有执行者对象) - 执行者

    23.备忘录模式

    同另一个类,存储当前类的所有有价值信息,不做修改等处理,只做get set操作

    24. 状态模式

    类似于QQ隐身、在线、忙碌的状态切换,不同状态会改变其行为。

    25. 访问者模式

    外部传入访问者对象

    接口
    public interface Visitor{
        public void visit(Subject sub);
    }
    访问类
    public class MyVisitor implements Visitor{
        public void visit(Subject sub){
            System.out.println("The visitor is:" + sub.getName());
        }
    }
    接受访问的类的接口
    public interface Subject{
        public void accept(Visitor visitor);
        public String getName();
    }
    接受访问的类的实现
    public class MySubject implements Subject{
        public void accept(Visitor visitor){
            visitor.visit(this);
        }
        public String getName(){
            return "LiuDehua";
        }
    }
    测试类:
    public class Test{
        public static void main(String[] args){
            Visitor visitor = new MyVisitor();
            Subject sub = new MySubject();
            sub.accept(visitor);
        }
    }
    输出结果
    The visitor is:LiuDehua
    
    26. 中介者模式

    两个类存在关系,又不想让他们彼此持有实例化对象,采用中介者调度。
    感觉类似于13 外观模式

    27. 解释器模式

    就是用来解释说明各种各样的类
    给定一个语言,定义他的文法的一种表示,并定义一个解释器,这个解释起使用该表示解释语言中的句子。
    一般用来存文法中终结符对应的具体值
    比如R=R1+R2,R1=100,R2=200;
    那么R1,R2,R的解释结果依次是100,200,300
    参考资料 《设计模式之笔记--解释器模式(Interpreter)》

    相关文章

      网友评论

        本文标题:2018-09-16 JAVA设计模式

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