您的位置:首页 > 编程语言 > Java开发

java提高之设计模式详解

2019-06-14 11:29 2061 查看

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

目标

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

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://www.geek-share.com/detail/2705496562.html

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

TODO

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: