设计模式:总结前人的经验,提供给后人借鉴。解决一些具有代表性的问题。
提升代码的可读性、可扩展性、维护成本、复杂的业务问题。
设计模式在应用中遵循六大原则:
a、开闭原则(Open Close Principle)
开闭原则就是说对扩展开放,对修改关闭。在程序需要进行拓展的时候,不能去修改原有的代码,实现一个热插拔的效果。所以一句话概括就是:为了使程序的扩展性好,易于维护和升级。想要达到这样的效果,我们需要使用接口和抽象类
b、里氏代换原则(Liskov Substitution Principle)
里氏代换原则(Liskov Substitution Principle LSP)面向对象设计的基本原则之一。 里氏代换原则中说,任何基类可以出现的地方,子类一定可以出现。 LSP 是继承复用的基石,只有当衍生类可以替换掉基类,软件单位的功能不受到影响时,基类才能真正被复用,而衍生类也能够在基类的基础上增加新的行为。里氏代换原则是对“开-闭”原则的补充。实现“开-闭”原则的关键步骤就是抽象化。而基类与子类的继承关系就是抽象化的具体实现,所以里氏代换原则是对实现抽象化的具体步骤的规范
c、依赖倒转原则(Dependence Inversion Principle)
这个是开闭原则的基础,具体内容:针对接口编程,依赖于抽象而不依赖于具体。
d、接口隔离原则(Interface Segregation Principle)
这个原则的意思是:使用多个隔离的接口,比使用单个接口要好。就是一个降低类之间的耦合度。
e、迪米特法则(最少知道原则)(Demeter Principle)
一个实体应当尽量少的与其他实体之间发生相互作用,使得系统功能模块相对独立。
f、合成复用原则(Composite Reuse Principle)
原则是尽量使用合成/聚合的方式,而不是使用继承
Spring中常用设计模式
IOC:工厂、单例
AOP:代理
SpringMVC:委派
JDBC:模板
设计模式分类:
创建型模式:指对象的创建,如工厂、单例、原型
结构型模式:指对类的再组织,如代理模式
行为型模式:
一:工厂模式
应用:开发过一套光猫巡检系统,光猫类型很多,使用工厂来创建,光猫有巡测、替换、删除功能
作坊-->工厂
1、提升产品质量
2、提高生产效率
3、扩大规模
4、标准化
用户不关心,产品(对象)是如何生产(创建)的,直接从工厂取出标准化的产品(对象)
简单工厂:适用于创建对象较少
public class MilkFactory {
//对象的创建由工厂来完成
public Milk getMilk(String milkName){
if(milkName!=null && milkName.equals("mengniu")){
return new Mengniu();
}else if(milkName!=null && milkName.equals("yili")){
return new Yili();
}
return null;
}
}
抽像工厂:
/**
* 抽象工厂
* 统一管理
* 易于扩展
*/
public abstract class AbstractFactory {
public abstract Milk getMengniu();
public abstract Milk getYili();
}
public class MilkFactory extends AbstractFactory{
@Override
public Milk getMengniu() {
return new Mengniu();
}
@Override
public Milk getYili() {
return new Yili();
}
}
二、单例模式
应用场景:配置信息
1、饿汉式
public class Hungry {
private Hungry(){};
//饿汉式单例,类加载时,即初始化
//优点:没有加锁、执行效率高,线程安全
//缺点:占用空间
public static final Hungry hungry = new Hungry();
public static Hungry getInstance(){
return hungry;
}
}
2、懒汉式
非线程安全
public class LazyOne {
private LazyOne(){};
private static LazyOne lazyOne = null;
//懒汉式,使用时创建
//优点:类加载时不占用空间
//缺点:非线程安全
public static LazyOne getInstance(){
if(lazyOne == null){
lazyOne = new LazyOne();
}
return lazyOne;
}
}
线程安全(方法锁)
public class LazyTwo {
private LazyTwo(){};
private static LazyTwo lazyTwo = null;
//懒汉式,使用时创建,为保证线程安全,加锁
//优点:类加载时不占用空间
//缺点:加锁后,影响性能
public synchronized static LazyTwo getInstance(){
if(lazyTwo == null){
lazyTwo = new LazyTwo();
}
return lazyTwo;
}
}
线程安全(块级锁)
public class LazyThree {
private LazyThree(){};
private static LazyThree lazyThree = null;
//懒汉式,使用时创建,为保证线程安全,加锁,锁代码块
public static LazyThree getInstance(){
if(lazyThree == null){
synchronized (LazyThree.class) {
if(lazyThree == null){
lazyThree = new LazyThree();
}
}
}
return lazyThree;
}
}
静态内部类
public class LazyFour {
private LazyFour(){};
//内部类方式,LazyFour调用时,才会加载内部类,且static的只会执行一次
private static class LazyFourInstance{
private static final LazyFour INSTANCE = new LazyFour();
}
public static LazyFour getInstance(){
return LazyFourInstance.INSTANCE;
}
}
防反射处理
private LazyFour(){
System.out.println("我执行了");
if(LazyFourInstance.INSTANCE != null){
throw new RuntimeException("不允许多实例");
}
};
反序列化处理
//反序列化,加入此方法,就会覆盖反序列化时创建的对象,虽然仍创建了两次对象,但最后使用的是同一个实例。
private Object readResolve(){
return LazyFourInstance.INSTANCE;
}
3、注册式
enum枚举
ThreadLocal:线程单例
三、原型模式
应用场景:DTO转VO(POJO),json转对象、集合。前端的VIEW对象,可以使用DTO对象复制。
使用原型实例创建新的对象,实现方式有:
1、遍历(最笨的方法):将原型实例的属性值遍历出来赋给新对象
2、拷贝(克隆):
浅拷贝:实现Cloneable接口,特点:基本数据类型赋值,引用数据类型赋地址
public class Student2 implements Cloneable{
private int id;
private String name;
public Student2(int id, String name) {
this.id = id;
this.name = name;
}
public int getId() {
return id;
}
public void setId(int id) {
this.id = id;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
@Override
public String toString() {
return "Student2{" +
"id=" + id +
", name='" + name + '\'' +
'}';
}
}
深拷贝:序列化,反序列化,拷贝对象
Student student = new Student(1,"chen",20);
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(student);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
Student student1 = (Student)ois.readObject();
oos.close();
ois.close();
3、反射:如BeanUtils.JSON
四、代理模式
给一个对象(原对象、被代理对象)提供一个代理对象,由代理对象去控制原对象(被代理对象)的使用,代理对象通常持有被代理对象的引用。代理对象增加了一些附加功能,遵从了开闭原则。
应用场景:AOP实现、拦截器、中介、黄牛。光猫巡测,不同光猫巡测前的登陆是一致的,可以用代理实现。
分类:静态代理、动态代理。动态代理也有比较成熟的轮子cglib
静态代理:编译后,代理类(.class)就存在了,代理之前,对被代理对象是已知的
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
/**
* 买房接口
*/
public interface BuyHouse {
public void buy();
}
/**
* 买房具体实现
*/
public class BuyHouseImpl implements BuyHouse{
@Override
public void buy() {
System.out.println("我买房子");
System.out.println("我筹钱");
System.out.println("我付款");
}
}
/**
* 中介
*/
public class HouseProxy{
private BuyHouse buyHouse;
public HouseProxy(BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
public void buyProxy() {
System.out.println("代理:找房子");
buyHouse.buy();
System.out.println("代理:协助合同签订");
}
}
public class Test {
public static void main(String[] args) {
BuyHouseImpl buyHouse = new BuyHouseImpl();
HouseProxy houseProxy = new HouseProxy(buyHouse);
houseProxy.buyProxy();
}
}
动态代理:通过反射实现,代理之前,对被代理对象是未知的
/**
* 动态中介,不用为每个中介对象去写一个中介类,具体中介的哪个类,由用户指定
*/
public class ZhongjieProxy implements InvocationHandler {
private BuyHouse target;
public BuyHouse getProxy(BuyHouse buyHouse) {
this.target = buyHouse;
Class clazz = target.getClass();
BuyHouse buyHouseProxy = (BuyHouse)Proxy.newProxyInstance(clazz.getClassLoader(),clazz.getInterfaces(),this);
return buyHouseProxy;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("中介:确认需求");
System.out.println("中介:找房子");
Object obj = method.invoke(target,args);
System.out.println("中介:签合同");
return obj;
}
}
BuyHouse buyHouse = new BuyHouseImpl();
//具体代理的哪个类,由用户指定
ZhongjieProxy dynamicProxy = new ZhongjieProxy();
//获取代理实例,这里不是BuyHouse对象,而是一个代理对象
BuyHouse buyHouseProxy = (BuyHouse)dynamicProxy.getProxy(buyHouse);
System.out.println(buyHouseProxy.getClass());
buyHouseProxy.buy();
System.out.println(buyHouseProxy.getClass());
Proxy.newProxyInstance核心代码
获得被代理对象所实现的接口,使用其构造器,创建代理实例。代理实例中的方法在执行时,会调用动态代理类的invoke方法。
final Class<?>[] intfs = interfaces.clone();
Class<?> cl = getProxyClass0(loader, intfs);
final Constructor<?> cons = cl.getConstructor(constructorParams);
cons.newInstance(new Object[]{h});
cglib实现
/**
* cglib实现动态代理,代理类不用继承接口
*/
public class CglibProxy implements MethodInterceptor {
// private Object target;
//
// public CglibProxy(Object target) {
// this.target = target;
// }
public Object getProxy(Class clazz){
Enhancer enhancer = new Enhancer();//cglib加强器
enhancer.setSuperclass(clazz);//目标类,对应了methodProxy.invokeSuper
enhancer.setCallback(this);//设置回调函数,即intercept
return enhancer.create();//创建代理对象
}
@Override
public Object intercept(Object o, Method method, Object[] objects, MethodProxy methodProxy) throws Throwable {
System.out.println("代理:日志处理,公共处理");
System.out.println("代理:准备工作");
Object obj = methodProxy.invokeSuper(o,objects);
System.out.println("代理:结束工作");
return obj;
}
}
public class Test {
public static void main(String[] args) {
// BuyHouseImpl buyHouse = new BuyHouseImpl();
// CglibProxy cglibProxy =
BuyHouseImpl buyHouseProxy = (BuyHouseImpl)new CglibProxy().getProxy(BuyHouseImpl.class);
buyHouseProxy.buy();
System.out.println(buyHouseProxy.getClass());
}
}
此处BuyHouseImpl,不需要实现接口
JDK动态代理是通过接口中的方法名,动态生成的代理类($Proxy0),代理类调用invoke方法(super.h.invoke(this, m3, null);//super是Proxy,h是InvocationHandler);
CGlib动态代理是通过继承业务类,生成的动态代理类是业务类的子类,通过重写业务方法进行代理;CGlib不能代理final的方法
五、策略模式
场景:支付选择,光猫选择(根据光猫名称,使用不同光猫,结合代理、工厂模式使用)
策略模式定义了一系列的算法(算法家庭),并将每一个算法封装起来,使每个算法可以相互替代,使算法本身和使用算法的客户端分割开来,相互独立。
public interface Payment {
/**
* 支付
*/
public void pay();
}
/**
* 阿里支付
*/
public class AlPay implements Payment{
@Override
public void pay() {
System.out.println("我是阿里支付");
}
}
/**
* 微信支付
*/
public class WxPay implements Payment{
@Override
public void pay() {
System.out.println("我是微信支付");
}
}
/**
* 支付方式枚举,历于扩展
*/
public enum PayType {
AL_PAY(new AlPay()),WX_PAY(new WxPay());
private Payment payment;
public Payment getPayment() {
return payment;
}
public void setPayment(Payment payment) {
this.payment = payment;
}
PayType(Payment payment) {
this.payment = payment;
}
}
/**
* 订单
*/
public class Order {
/**
* 订单支付
*/
public void pay(Payment payment){
payment.pay();
}
}
public class Test {
public static void main(String[] args) {
Order order = new Order();
order.pay(PayType.AL_PAY.getPayment());
}
}
六、模板模式
定义一个操作中算法的骨架,而将一些步骤延迟到子类中,模板方法使得子类可以不改变算法的结构即可重定义该算法的某些特定步骤。
通俗点的理解就是 :完成一件事情,有固定的数个步骤,但是每个步骤根据对象的不同,而实现细节不同;就可以在父类中定义一个完成该事情的总方法,按照完成事件需要的步骤去调用其每个步骤的实现方法。每个步骤的具体实现,由子类完成。
如去银行办业务,如取钱,存钱或者办卡等,基本都需要三个大的步骤(骨架),首先 (1)取号 (2)办具体业务 (3)服务评价打分,然后这三个步骤就可以抽取到父类中进行定义,(1)取号 (3)服务打分是相同操作,可以直接在父类总实现,然后(2)办具体的业务各不相同需要在子类中实现
父类是一个抽象类,相同的方法在父类里实现,不同的地方在子类中实现
还有ORM
应用场景:其实光猫巡测,也可用模板模式,不同型号的光猫,登陆和退出是一样的,这一块可以单独抽取出来,做为父类。
public abstract class AbstractDao {
/**
* 查询
* @param sql
* @param params
* @return
*/
protected Object find(String sql, Object[] params) {
Connection conn = null;
PreparedStatement ps = null;
ResultSet rs = null;
Object obj = null;
try {
conn = JDBCUtils.getConnection();
ps = conn.prepareStatement(sql);
for (int i = 0; i < params.length; i++) {
ps.setObject(i + 1, params[i]);
}
rs = ps.executeQuery();
while (rs.next()) {
obj = rowMapper(rs);
}
} catch (Exception e) {
e.printStackTrace();
} finally {
JDBCUtils.free(rs, ps, conn);
}
return obj;
}
protected abstract Object rowMapper(ResultSet rs) throws SQLException;
//同时可以添加 insert ,update 等方法
}
/**
* userDao
*
* @author aries
*
*/
public class UserDao extends AbstractDao {
public User findUser(int userId) {
String sql = "select * from t_user where userId = ?";
Object[] params = new Object[] { userId };
Object user = super.find(sql, params);
System.out.println((User) user);
return (User) user;
}
@Override
protected Object rowMapper(ResultSet rs) throws SQLException {
User user = new User();
user.setId(rs.getInt("userId"));
user.setName(rs.getString("name"));
user.setAge(rs.getInt("age"));
user.setSex(rs.getString("sex"));
user.setAddress(rs.getString("address"));
return user;
}
}
七、适配器模式
适配器就是为了适配,如生活中的各种转接头,就是适配器
老系统升级新系统,就可以采用适配器模式,在老系统之上,再封装一层,用来做适配
不改变老的代码,就能适应新的需求,目的是为了兼容
/**
* 两孔插座
*/
public class TwoHoleSocket {
public void provideElec(){
System.out.println("通过两孔插座提供电源");
}
}
/**
* 三孔插座接口
*/
public interface ThreeHoleSocketInter {
public void provideElec();
}
/**
* 插座适配器
*/
public class SocketAdapter implements ThreeHoleSocketInter{
private TwoHoleSocket twoHoleSocket;
public SocketAdapter(TwoHoleSocket twoHoleSocket) {
this.twoHoleSocket = twoHoleSocket;
}
/**
* 通过三孔提供电源
*/
public void provideElec(){
System.out.println("通过三孔提供电源,其中是个转接头,真正提供电源的二孔插座");
twoHoleSocket.provideElec();
}
}
/**
* 国产电脑
*/
public class Computer {
private ThreeHoleSocketInter threeHoleSocketInter;
public Computer(ThreeHoleSocketInter threeHoleSocketInter) {
this.threeHoleSocketInter = threeHoleSocketInter;
}
/**
* 充电
*/
public void charge(){
System.out.println("我需要通过三孔插头进行充电");
threeHoleSocketInter.provideElec();
}
}
public class Test {
public static void main(String[] args) {
SocketAdapter adapter = new SocketAdapter(new TwoHoleSocket());
Computer computer = new Computer(adapter);
computer.charge();
}
}
八、装饰器模式
装饰器模式,顾名思义,就是对已经存在的某些类进行装饰,以此来扩展一些功能。
应用场景:IO流
/**
* 车接口
*/
public interface Car {
/**
* 获得一辆车
*/
public void getCar();
}
public class BenChi implements Car{
@Override
public void getCar() {
System.out.println("我是一辆奔驰车");
}
}
public class DaZhong implements Car{
@Override
public void getCar() {
System.out.println("我是一辆大众车");
}
}
/**
* 靠枕适配器
*/
public class KaoZhenDecorator implements Car{
private Car car;
public KaoZhenDecorator(Car car) {
this.car = car;
}
@Override
public void getCar() {
car.getCar();
System.out.println("我加了靠枕");
}
}
public class ShaFaDecorator implements Car{
private Car car;
public ShaFaDecorator(Car car) {
this.car = car;
}
@Override
public void getCar() {
car.getCar();
System.out.println("我加了真皮沙发");
}
}
public class Test {
public static void main(String[] args) {
Car car = new ShaFaDecorator(new KaoZhenDecorator(new BenChi()));
car.getCar();
}
}
九、观察者模式
定义对象之间的一对多的依赖关系,当一个对象状态改变时,所有依赖于它的对象得到通知,并进行更新。
应用场景:事件监听、日志监听、短信通知
/**
* 观察者接口
*/
public interface Observer {
/**
* 被观察者变更时,通过此方法通知观察者
* @param message
*/
public void update(String message);
}
/**
* 可被观察接口,也被称为目标对象subject
*/
public interface Observerable {
/**
* 添加观察者
*/
public void addObserver(Observer observer);
/**
* 移除观察者
*/
public void removeObserver(Observer observer);
/**
* 通知所有观察者
*/
public void notifyObserver(String message);
}
/**
* 气象站
*/
public class WeatherStation implements Observerable{
private List<Observer> observerList;
public WeatherStation() {
this.observerList = new ArrayList<>();
}
public List<Observer> getObserverList() {
return observerList;
}
public void setObserverList(List<Observer> observerList) {
this.observerList = observerList;
}
@Override
public void addObserver(Observer observer) {
observerList.add(observer);
}
@Override
public void removeObserver(Observer observer) {
observerList.remove(observer);
}
@Override
public void notifyObserver(String message) {
for (Observer observer : observerList){
observer.update(message);
}
}
public void getWeather(){
System.out.println("气象站获取天气情况");
notifyObserver("天气变了");
}
}
/**
* 站点
*/
public class WebSite implements Observer{
private String name;
public WebSite(String name) {
this.name = name;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public void update(String message) {
System.out.println("我是"+name+",我知道:"+message);
}
}
public class Test {
public static void main(String[] args) {
WebSite webSite1 = new WebSite("新浪");
WebSite webSite2 = new WebSite("腾讯");
WeatherStation station = new WeatherStation();
station.addObserver(webSite1);
station.addObserver(webSite2);
station.getWeather();
}
}
十、委派模式
委派模式不是23种设计模式之一,与代理模式比较像。
代理模式更关注被代理对象的功能增强,如前置操作、后置操作。而委派模式量多注重结果,其基本作用就是负责任务的调用和分配任务。
如Boss给项目经理一个系统开发任务。项目经理会将产品设计、UI、前端、系统架构、后端、数据库工作分配给不同的人来完成。这就是分配任务。
SpringMVC中的DispatcherServlet,就是委派模式
- 大小: 16.2 KB
分享到:
相关推荐
主要是介绍各种格式流行的软件设计模式,对于程序员的进一步提升起推进作用,有时间可以随便翻翻~~ 23种设计模式汇集 如果你还不了解设计模式是什么的话? 那就先看设计模式引言 ! 学习 GoF 设计模式的重要性 ...
Java 经典设计模式讲解以及项目实战 设计模式简介:主要介绍各种设计模式的概念和运用场景等 设计模式综合运用:主要是笔者在实际工作中运用到的一些设计模式综合运用事例的提炼 Spring设计模式简介:主要是讲述...
设计模式 的分类 总体来说设计模式分为三大类: 创建型模式(5): 工厂方法模式 、抽象工厂模式、单例模式、建造者模式、原型模式。 结构型模式(7): 适配器模式、装饰器模式、代理模式、外观模式、桥接模式、...
GOF(Gang of Four)设计模式,由Erich Gamma、Richard Helm、Ralph Johnson和John Vlissides四位专家在他们的著作《设计模式:可复用面向对象软件的基础》中提出,被誉为设计模式的经典之作。本资源包含了GOF设计...
《Head First 设计模式》与《Java设计模式(第2版)》是两本非常重要的IT书籍,专注于软件开发中的设计模式。设计模式是解决软件设计中常见问题的经验总结,它们提供了一种标准的方法来处理特定场景下的问题,使得代码...
### 设计模式解析:深入理解软件设计的核心原则与实践 #### 标题解析:设计模式解析 设计模式是软件工程领域的重要概念,旨在提供解决常见软件设计问题的模板或指导原则。《设计模式解析》这一标题暗示了书籍将...
根据提供的文档概览,我们可以对每个章节所涉及的设计模式进行详细的阐述和解释。下面将针对文档中提及的设计模式逐一展开,以便更好地理解这些模式的概念、结构、应用场景以及优缺点。 ### 1. 面向对象程序设计...
这个压缩包文件"设计模式(包含5个设计模式)含源代码报告.rar"显然是一份宝贵的资源,它涵盖了五个核心的设计模式,并附带了详细的类图、源代码以及文档报告,这对于学习和理解设计模式至关重要。 首先,我们要探讨...
在计算机科学领域,设计模式是软件工程中用于解决特定问题的一般性方案,它们是经过实践检验的最佳实践。这些模式被广泛应用于面向对象软件设计中,能够提高代码的可重用性、灵活性和可维护性。设计模式通常被划分为...
本系统基于六种设计模式,运用到的设计模式有备忘录模式,简单工厂模式,迭代器模式,状态模式,模版方法模式,单例模式。 具体实现过程、UML类图以及实现效果详见如下项目说明地址: ... 该系统为绘图系统,该系统通过...
软件设计模式(Java版)习题答案 本资源为软件设计模式(Java版)习题答案,由程细柱编著,人民邮电出版社出版。该资源涵盖了软件设计模式的基础知识,包括软件设计模式的概述、UML中的类图、面向对象的设计原则、...
设计模式精解- GoF 23种设计模式解析附C++实现源码 懂了设计模式,你就懂了面向对象分析和设计(OOA/D)的精要。反之好像也可能成立。道可道,非常道。道不远人,设计模式亦然如此。 一直想把自己的学习经验以及在...
全书用两章篇幅对设计模式和GRASP作了基本介绍,3种设计模式的讲解:对于每一种模式,先给出定义,接着通过类比方式用一个现实世界中的例子说明模式的应用,然后分别以C#和Java代码例述模式的架构实现。最后一章给出...
资源名称:MongoDB应用设计模式内容简介:无论是在构建社交媒体网站,还是在开发一个仅在内部使用的企业应用程序,《MongoDB应用设计模式》展示了MongoDB需要解决的商业问题之间的连接。你将学到如何把MongoDB设计...
设计模式是软件开发中的经典实践,它们为解决特定问题提供了通用、可复用的解决方案。在Java编程中,运用合适的设计模式可以提高代码的可维护性、可扩展性和可复用性。以下是关于Java版本设计模式实现demo的一些补充...
设计模式是软件工程中的一种最佳实践,它是在特定上下文中解决常见问题的经验总结。"设计模式之美——教你写出高质量代码"这个主题旨在帮助开发者更好地理解和应用设计模式,从而提升代码的质量和可维护性。设计模式...
章节介绍:1、爪哇语言结构性模式之变压器模式介绍 2、爪哇语言抽象工厂创立性模式介绍 3、工厂方法创立性模式介绍 4、单态创立性模式介绍 5、单态创立性模式介绍 6、观察者模式介绍7、责任链模式 8、设计模式之...
在软件开发领域,设计模式是经过时间和实践验证的解决方案模板,用于解决常见问题。本作业以“软件设计模式”为主题,特别关注了装饰模式、工厂模式和适配器模式的运用。这三种模式都是面向对象设计的核心部分,它们...