java提高之设计模式详解

对设计模式认识比较肤浅,需要总结的比较通俗,可能部分失真,等以后随着实践和认知能力的提升,对文章再行完善。

目标

  • 设计模式的六大原则
  • 设计模式的划分
  • 构建者模式
  • 装饰器模式
  • 工厂模式

1. 六大原则

1. 单一职责原则

Single Responsibility Principle, SRP,一个类只负责一个功能领域的相应职责。也就是我们常说的“高内聚,低耦合”

2. 开闭原则

Open-Closed Principle,OCP:对扩展开放,对修改关闭

也就是尽量在不修改原有代码的情况下进行扩展

3. 里式替换原则

Liskov Substitution Principle,LSP:所有引用父类的地方必须能透明的使用其子类的对象。

在程序中尽量使用基类类型来对对象进行定义,在运行时再确定子类类型,用子类对象来替换父类对象。

算是实现开闭原则的重要方式之一,通俗的说:子类可以扩展父类的功能,但不能改变父类原有的功能

4. 依赖倒置原则

Dependency Inversion Principle,DIP:抽象不应该依赖于细节,细节应该依赖于抽象,也就是面向接口编程,而不是针对实现编程

开闭原则是目标,里式替换是基础,依赖倒置是手段。

感觉和spring的DI有点联系,后续再思考。

5. 接口隔离原则

Interface Segregation Principle,ISP:使用多个专门的接口,而不适用单一的总接口,即客户端不应该依赖那些它不需要的接口

每个接口应该承担相对独立的角色,提供定制服务,当然接口也不能太小,灵活性会变差。控制好接口的粒度。

6. 迪米特法则

Law of Demeter,LoD, 也叫最少知识原则,LeastKnowledge Principle,LKP:一个软件实体应当尽可能少的与其他实体发生相互作用

也就是解耦合,降低系统的耦合度。

2. 分类

大致按照设计模式的应用目标分类,分为创建型、结构型和行为型

  • 创建型模式,是对对象创建过程的各种问题和解决方案的总结,包括各种工厂模式(Factory, Abstract Factory)、单例模式(Singleton)、构建者模式(Builder)、原型模式(Prototype)
  • 结构型模式,是对软件设计结构的总结,专注于类、对象继承、组合方式的实践经验。常见的有桥接模式(Bridge)、适配器模式(Adapter)、装饰器模式(Decorator)、代理模式(Proxy)、组合模式(Composite)、门面模式(Facade)、享元模式(Flyweight)等。
  • 行为型模式,是从类或者对象之间交互、职责划分等角度总结的模式,常见有策略模式(Strategy)、解释器模式(Interpreter)、命令模式(Command)、观察者模式(Observer)、迭代器模式(Iterator)、模板方法模式(Template Method)、访问者模式(Visitor)

如果想快速了解各个模式的作用,可以参考 追MM与设计模式 https://blog.csdn.net/u011676417/article/details/70879632

3. 常用模式

1. 单例模式

之前总结有,https://blog.csdn.net/wjl31802/article/details/91360815

单例模式最常见,必须掌握

2. 装饰器模式

1. 典型使用场景

IO框架里面,InputStream是个抽象类,标准类库中提供了FileInputStream、ByteArrayInputStream等各种不同的子类,分别从不同角度对InputStream进行功能扩展。

2. 概念

本质上是包装同类型实例。我们对目标对象的调用,通过包装类覆盖过的方法,迂回调用被包装的实例,实现增加额外逻辑的目的,也就是“装饰”。

如BufferedInputStream为输入流增加了缓存。

优点:装饰类和被装饰类可以独立发展,不会耦合,是继承的一个替代模式

缺点:多层装饰较为复杂

使用场景:1. 扩展一个类的功能 2. 动态增加功能或撤销功能

3. 代码实现

为长方形和圆添加红边装饰

主要有几个类

接口

public interface Shape {
    void draw();
}

实现类

public class Rectangle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Rectangle");
    }
}
public class Circle implements Shape {
    @Override
    public void draw() {
        System.out.println("Shape: Circle");
    }
}

创建抽象装饰类

public abstract class ShapeDecorator implements Shape {
    protected Shape decoratedShape;

    public ShapeDecorator(Shape decoratedShape){
        this.decoratedShape = decoratedShape;
    }

    @Override
    public void draw() {
        decoratedShape.draw();
    }
}

创建实体装饰类

public class RedShapeDecorator extends ShapeDecorator {
    public RedShapeDecorator(Shape decoratedShape) {
        super(decoratedShape);
    }

    @Override
    public void draw() {
        decoratedShape.draw();
        setRedBorder(decoratedShape);
    }

    private void setRedBorder(Shape decoratedShape){
        System.out.println("Border Color: Red");
    }
}

实例,用RedShapeDecorator装饰Shape对象

public class DecoratorPatternDemo {
    public static void main(String[] args) {
        Shape circle = new Circle();
        ShapeDecorator redCircle = new RedShapeDecorator(new Circle());
        ShapeDecorator redRectangle = new RedShapeDecorator(new Rectangle());
        System.out.println("Circle with normal border");
        circle.draw();

        System.out.println("\nCircle of red border");
        redCircle.draw();

        System.out.println("\nRectangle of red border");
        redRectangle.draw();
    }
}

3. 构建者模式

1. 概念

比较优雅的解决构建复杂对象的麻烦,这里的“复杂”指的是类似需要输入的参数组合较多。如果用构造函数,需要为每一种可能的组合实现相应的构造函数,代码阅读星和可维护性差。

实质:从结构上把对象的使用逻辑和创建逻辑相互独立,隐藏对象实例的细节,为使用者提供更加规范、统一的逻辑。

典型的构造者模式,通常会被实现成fluent风格的API,也叫方法链。

以我们最常见的StringBuilder为例,append方法里面可能写String、char[ ]、int、long等等,该构建者为我们提供了统一的append方法,无需再写各种构造方法。非常方便。它的append后边可以再加其他方法,形成链。

2. 代码实现
public class Student {
    private int id;
    private String name;
    private String password;
    private String sex;
    private String address;

    // 构造器尽量缩小范围
    private Student(){}

    private Student(Student origin){
        // 拷贝一份
        this.id = origin.id;
        this.name = origin.name;
        this.password = origin.password;
        this.sex = origin.sex;
        this.address = origin.address;
    }

// getter/setter

    public static class Builder{
        private Student target;
        public Builder(){
            target = new Student();
        }
        public Builder name(String name){
            target.name = name;
            return this;
        }

        public Builder password(String passwd) {
            target.password = passwd;
            return this;
        }

        public Builder sex(String sex) {
            target.sex = sex;
            return this;
        }

        public Builder address(String address) {
            target.address = address;
            return this;
        }
        public Student build(){
            return new Student(target);
        }
    }
}

使用的话,

Student s = new Student.Builder().name("cc").password("123").sex("男").address("北京东长安街").build();

4. 工厂模式

最常见,创建对象的最佳方式,解耦

贴近实战,直接看spring的beanFactory工厂的诞生,自定义实现(也用到了单例模式)

public class MyBeanFactory {
    // 定义一个properties对象
    private static Properties properties;

    // 静态代码块为对象赋值
    static {
        InputStream in = MyBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        properties = new Properties();
        try {
            properties.load(in);

        } catch (IOException e) {
            throw new ExceptionInInitializerError("初始化properties失败");
        }
    }

    public static Object getBean(String beanName){
        Object bean = null;
        // 根据beanName获取对象
        String beanPath = properties.getProperty(beanName);
        try {
            // class.forName("全类名")获取class对象
            bean = Class.forName(beanPath).newInstance();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        return bean;
    }
}

​ 这样的工厂貌似可以实现功能,但是不是单例模式,每次都得到有个船新?的对象,很显然不符合我们的期望,效率较低

public class MyBeanFactory {
    // 定义一个properties对象
    private static Properties properties;
    
    // 用一个map容器来存储这些对象
    private static Map<String,Object> beans;

    // 静态代码块为对象赋值
    static {
        InputStream in = MyBeanFactory.class.getClassLoader().getResourceAsStream("bean.properties");
        properties = new Properties();
        try {
            properties.load(in);

        } catch (IOException e) {
            throw new ExceptionInInitializerError("初始化properties失败");
        }
        // map进行初始化
        beans = new HashMap<String, Object>();
        // 获取properties里面的key
        Enumeration<Object> keys = properties.keys();
        while(keys.hasMoreElements()){
            // 得到每一个key
            String key = keys.nextElement().toString();
            // 得到对应的beanPath
            String beanPath = properties.getProperty(key);
            Object value = null;
            // 获取value的object
            try {
                value = Class.forName(beanPath).newInstance();
            } catch (InstantiationException e) {
                e.printStackTrace();
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
            // 将key和value存到map中
            beans.put(key,value);
        }
    }
}

5. 观察者模式

1. 概念

当对象间存在一对多关系时,使用观察者模式(Observer Pattern)。当一个对象(Observable)被修改,会自动通知它的依赖对象观察者(Observer)。

zookeeper就是观察者模式的典型代表

2. 相关API

java的API中提供Observable抽象类和Observer接口,构成对观察者模式的支持

1. java.util.Observable

被观察者,可将其子类化,未指定发送通知的顺序

常用方法:

  • addObserver(Observer o) 向观察者集中添加观察者们

关键代码:类中有个set集合存放观察者们

// Adds an observer to the set of observers
public synchronized void addObserver(Observer o) {
  if (o == null)
    throw new NullPointerException();
  if (!obs.contains(o)) {
    obs.addElement(o);
  }
}
  • protected void setChanged() 标记此Observable对象为已改变的对象,hasChanged方法将返回true
  • boolean hasChanged() 测试对象是否改变
  • void notifyObservers(Object arg) 如果hasChanged方法指示对象已改变,通知所有观察者
  • void deleteObserver(Observer o) 从观察者集合中删除某个观察者
2. Observer接口

观察者接口。可得到被观察者的更改通知

  • void update(Observable o, Object arg) 只要改变了Observable对象就通知它
3. 代码实现
public class User implements Observer {

    private String name; // 用户名

    public User(String name){
        this.name = name;
    }

    @Override
    public void update(Observable o, Object arg) {
        System.out.println("微信用户:"+name+",您订阅的公众号更新了以下内容:"+arg);
    }
}
public class OfficialAccount extends Observable {

    public void pushNewInfo(String info){
        // 标记对象已改变
        setChanged();
        // 推送通知,需要先检测changed状态
        notifyObservers(info);
    }
}
public class Test {
    public static void main(String[] args) {
        User tom = new User("tom");
        User jack = new User("jack");
        User pony = new User("pony");

        OfficialAccount officialAccount = new OfficialAccount();
        officialAccount.addObserver(tom);
        officialAccount.addObserver(jack);
        officialAccount.addObserver(pony);

        officialAccount.pushNewInfo("亲,非常抱歉,今天停更一天");
        officialAccount.deleteObserver(tom);
        officialAccount.pushNewInfo("明天早上不见不散哈,亲");
    }
}

TODO

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值