网站开发团队 人员,优设网app安卓下载,响应式网站公司,网站代码检查什么是设计模式 简单来说#xff0c;设计模式就是很多程序员经过相当长的一段时间的代码实践、踩坑所总结出来的一套解决方案#xff0c;这个解决方案能让我们少写一些屎山代码#xff0c;能让我们写出来的代码写出来更加优雅#xff0c;更加可靠。所以设计模式的好处是显而…什么是设计模式 简单来说设计模式就是很多程序员经过相当长的一段时间的代码实践、踩坑所总结出来的一套解决方案这个解决方案能让我们少写一些屎山代码能让我们写出来的代码写出来更加优雅更加可靠。所以设计模式的好处是显而易见的。 当然设计模式不仅仅能够让我们写出更好的代码他还有些好处 我们在读框架、中间件源码的时候我们会设计模式就能够更好的去理清源码的整个逻辑读起来也会轻松不少。面试的时候设计模式还是问的比较多的所以呢设计模式学得好工作少不了。
七大设计原则
单一职责原则 Single ResponsibilityPrinciple
一个类应该只有一个发生变化的原因否则类应该被拆分 用我们自己的话来说就是一个类只负责一项职责、只做一件事情也就是说要做到代码功能的原子性比如说我们在 做项目的时候用户模块里就只处理用户相关的业务商品服务里就只处理商品相关的业务这样他们就不会互相影响 了就解耦开来了。 开闭原则 Open Closed Principle
对扩展开放、对修改关闭 意思就是我们写代码的时候尽量在已有的代码上做扩展比如说新增模块新增方法而不是去修改别人已经写好的代码。 这个估计大家感受很深刻写代码最痛苦的事情就是在别人的代码上做迭代了。当然这个原则上是尽量要这样实际工作中如果你的需求只要在别人的代码上改动非常少的代码就能实现那我们也可以不要遵守这个原则了。 里氏替换原则 Liskov SubstitutionPrinciple
子类对象是可以替换程序中父类对象出现的任何地方并且保证原来的程序逻辑不变以及运行正确 换句话说就是子类可以扩展父类的功能但不能去改变父类原有的功能。 接口隔离原则 Interface Segregation Principle
写代码的时候接口不要写得太臃肿了我们需要把接口拆分得更小更专用。
依赖倒置原则 Dependency Inversion Principle
设计代码结构时高层模块不应依赖低层模块两者都应该依赖抽象抽象不应依赖细节细节应该依赖抽象。
KISS 原则 keep it simple and stupid
保持它的简单和愚蠢。 也就是说我们的代码尽量要写得简单不要为了炫技来写很多花里胡哨的代码比如说一个代码只要几个if else就能解 决了而且后期几乎不可能再去升级那这种代码其实就没必要用什么设计模式去做了这样倒是搞得代码更加复杂 了。所以咱们写代码尽量不要用同事不懂的技术来写代码也不要去重复造轮子尽量用目前市面上比较成熟的开 源库也不要做过度优化把一些简单的代码弄得花里胡哨的。 YAGNI 原则 you ain’t gonna need it
你不需要它。 就是不要去做一些过度设计比如说公司只用得到MySQL你为了以后能够支持海量数据直接把hadoop那套体系搬过来了各种技术都引入进来那是完全没有必要的。 DRY 原则 don’t repeat your code
不要写重复的代码。
迪米特法则 law of demeter 他的核心主旨就是一个对象应该对其他对象保持最少的了解也就是多个类之间尽量不要直接去依赖如果你非要依赖那也只能依赖必要的接口。其实也就是为了减少类和类之间的耦合每个类越独立越好。这个其实就是我们正常开发中用到的策略直接依赖接口而不是依赖实现类。 设计模式分类
创建型5种处理对象的创建过程工厂方法模式、抽象工厂模式、单例模式、建造者模式、原型模式结构型7种处理类或者对象的组合适配器模式、装饰器模式、代理模式、外观模式、桥接模式、组合模 式、享元模式行为型11种对类或对象怎样交互和怎样分配职责进行描述策略模式、模板方法模式、观察者模式、迭代器模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式
对应到我们的编码开发过程其实是一个有先后顺序的递进过程我们来看一下 首先我们要去实现某个功能肯定会要创建对象是吧所以像单例、工厂、建造者、原型都属于怎样去很好的创建对象主要目的在于将对象的创建与使用分离然后对象创建好了之后就应该去考虑对象之间关系如何更好的继承、依赖、组合那么就衍生了很多结构型的模式比如门面、适配器、代理、装饰、组合、享元这些最后前面2步做完了就到了具体实现怎样更好的达到目的使行为更加清晰、效率更高就是行为型模型 要做的事情比如策略责任链、迭代器等等 工厂模式 工厂Factory顾名思义创建对象实例的生产工厂以前我们创建对象都是 new Xxx()如果我们使用工厂模式 的话就可以用它来替代 new 操作创建实例对象所以当你理解了工厂模式后以后去 new 对象时就可以考 虑还能使用工厂模式达到一样的目的虽然这样做可能需要多做一些工作但会给你系统带来更大的可扩展性和尽 量少的修改量主要是 降低耦合 工厂模式分为 3 种包括简单工厂模式、工厂方法模式、抽象工厂模式接下来我们逐一来看
简单工厂模式 简单工厂模式不属于 GOF 的 23 种经典设计模式严格来说它应该属于一种编程习惯这个简单工厂模式只是工厂方法模式的一种特例所以工厂模式实际上只有工厂方法模式和抽象工厂模式。 简单工厂核心逻辑其实就是这样将一堆 if else 判断从业务代码中剥离出来然后塞到一个工厂类中通过这个工厂来生产出我们想要的产品。这样我们在业务中就不需要关心这种逻辑了一切都由工厂给我提供就像你去买一个手机一样你根本不用关心这个手机是怎么通过流水线生产出来的就像我们这个代码里也不用去关心这个上传服务实例是怎么生成的。 工厂方法模式
工厂方法核心思想是将对象的创建逻辑下沉到子类里面创建多个子工厂来创建对象。 这种方式如果再要增加第三方上传服务时就不需要修改工厂类的代码了每个第三方服务都会有一个工厂这样就解决了简单工厂模式的缺点不过要相应地增加工厂类工厂方法模式是简单工厂模式的进一步抽象运用了多态性、克服了简单工厂模式的缺点。 优点获取对象时只需要知道具体工厂的名称就可以得到对应的对象无须知道具体创建过程在系统增加新的类 时只需要添加对应的具体工厂类无须对原工厂进行任何修改满足开闭原则 缺点每增加一个类就要增加一个对应的具体工厂类增加了系统的复杂度 抽象工厂模式 抽象工厂模式直接通过案例分析 定义了两个接口ThirdPartyPush 和ThirdPartySMS它们分别代表了第三方推送和短信服务。创建了两个具体的类TencentThirdPartyPush 和TencentThirdPartySMS它们实现了 ThirdPartyPush和 ThirdPartySMS 接口分别表示腾讯的推送短信服务。创建了另外两个具体的类AliThirdPartyPush 和AliThirdPartySMS它们也实现了 ThirdPartyPush 和ThirdPartySMS 接口分别表示阿里的推送和短信服务。定义了一个抽象工厂类 ThirdPartyTotalFactory它包含两个抽象方法 createPusher 和 createSmser用于创建不同厂商的推送服务和短信服务。创建了具体的工厂类 AliFactory 和 TencentFactory它们分别继承了 ThirdPartyTotalFactory 并实现了工厂类的抽象方法。AliFactory 用于创建阿里厂商的推送和短信服务而 TencentFactory 用于创建腾讯厂商的推送和短信服务。使用抽象工厂模式创建不同厂商的推送和短信服务并通过工厂方法将它们与具体的厂商实现解耦。这有助于现松耦合和易维护的代码结构。 public interface ThirdPartyPush {String push();
}
public interface ThirdPartySMS {String send();
}
public class TencentThirdPartyPush implements ThirdPartyPush {Overridepublic String push() {return 腾讯推送;}
}
public class TencentThirdPartySMS implements ThirdPartySMS {Overridepublic String send() {return 腾讯短信发送;}
}
public class AliThirdPartyPush implements ThirdPartyPush {Overridepublic String push() {return 阿里推送;}
}
public class AliThirdPartySMS implements ThirdPartySMS {Overridepublic String send() {return 阿里短信发送;}
}
public abstract class ThirdPartyTotalFactory {abstract ThirdPartyPush createPusher();abstract ThirdPartySMS createSmser();
}
public class AliFactory extends ThirdPartyTotalFactory {OverrideThirdPartyPush createPusher() {return new AliThirdPartyPush();
}OverrideThirdPartySMS createSmser() {return new AliThirdPartySMS();}
}
public class TencentFactory extends ThirdPartyTotalFactory {OverrideThirdPartyPush createPusher() {return new TencentThirdPartyPush();
}OverrideThirdPartySMS createSmser() {return new TencentThirdPartySMS();}
}
单例设计模式Singleton Design Pattern
理解起来非常简单。就是不管在任何情况下一个类只能有一个对象。
饿汉式 这种方式在类加载的时候就把服务实例初始化好了所以这一步其实是线程安全的不会说在多线程的环境下创建出很多个实例了。这种方式在对象类加载的时候就实例化了所以其实有可能会造成一个问题就是内存浪费因为你不确定这个对象会不会使用所以就会有一个懒汉式的模式这个模式可以让我们在需要发短信的时候才创建这个实例对象而不是一开始类加载的时候就创建。但是这个问题其实也不是问题因为我们在项目中写代码一定是有我们自己的考量的。当写了一个发送短信的服务 后不可能说这个服务以后都不会调用的。而且假设这种实例占用内存太多那我们最好是能够在启动的时候就创建好这样假如说有OOM的这种问题我们也能及时发现就是有问题我们要及时暴露出来不要等到项目上线了才暴露出问题来那样就很严重了。 public class SendSmsServiceHungrySingleton {
private static final SendSmsServiceHungrySingleton instance newSendSmsServiceHungrySingleton();
private SendSmsServiceHungrySingleton() {}public static SendSmsServiceHungrySingleton getInstance() {return instance;}public String sendSms() {System.out.println(发送短信);return OK;}
}懒汉式 饿汉式是比较饥饿它立马就要拿到这个对象实例懒汉就是比较懒它要等到调用的时候才创建对象实例。 这里就是直接在 getInstance 方法里面判断一下这个实例有没有初始化没有的话我就初始化一下已经初始化了就直接返回。 public class PushServiceLazySingleton {private static PushServiceLazySingleton instance;private PushServiceLazySingleton() {}public static PushServiceLazySingleton getInstance() {if(instance null) {instance new PushServiceLazySingleton();}return instance;}
}这种方式实现起来还是比较简单的代码逻辑很清晰。但是这种方式其实在多线程的环境下是有问题的它完全没办法保证我的项目里只会创建一个instance对象。 双重检查锁 所以我们引入一个新的解决方案就是双重检查锁。这个锁什么意思我们看代码就清楚了。
public class PushServiceLazyDoubleCheckSingleton {private static PushServiceLazyDoubleCheckSingleton instance;private PushServiceLazyDoubleCheckSingleton() {}public static PushServiceLazyDoubleCheckSingleton getInstance() {// 1. 第一次检查 instance 是否已经实例化if(instance null) {synchronized(PushServiceLazyDoubleCheckSingleton.class) {// 2. 第二次检查 instance 是否已经实例化if(instance null) {instance new PushServiceLazyDoubleCheckSingleton();}}}return instance;}
}这种情况下其实还是有问题的在一些极端的场景下可能会有一个指令重排的问题。
静态内部类 还可以采用静态内部类的方式同样也是利用了类的加载机制它与饿汉模式不同的是它是在内部类里面去创建对象实例。这样的话只要应用中不使用内部类JVM就不会去加载这个单例类也就不会创建单例对象从而实现懒汉式的延迟加载。也就是说这种方式可以同时保证延迟加载和线程安全。 public class LazyStaticInnerClassSingleton {private LazyStaticInnerClassSingleton(){//解决反射破坏因为反射可以调用私有的构造器if(LazyHolder.INSTANCE ! null){throw new RuntimeException(不允许非法访问);}}
public static LazyStaticInnerClassSingleton getInstance(){return LazyHolder.INSTANCE;
}private static class LazyHolder{
private static final LazyStaticInnerClassSingleton INSTANCE new LazyStaticInnerClassSingleton();}
}注册式
枚举单例 枚举类实现单例模式是极力推荐的单例实现模式因为枚举是线程安全的并且只会装载一次枚举类是所有单例类 实现中唯一不会被破坏的单例模式解决了反射与序列化破坏 public enum SendServiceEnum {
INSTANCE;public static SendServiceEnum getInstance(){return INSTANCE;}public String send() {System.out.println(发送短信);return OK;}
}容器式单例
public final class ContainerSingleton {
private ContainerSingleton() {}
private static final ConcurrentHashMapString, Object instanceMap new ConcurrentHashMap();
public static T T get(String key,SupplierT supplier) {
T instance null;
if(!instanceMap.contains(key)) {
synchronized(ContainerSingleton.class) {
if(!instanceMap.contains(key)){instance supplier.get();instanceMap.put(key,instance);
}else {instance (T)instanceMap.get(key);
}
return instance;
}
}else {
return (T) instanceMap.get(key);
}
}
}