200字范文,内容丰富有趣,生活中的好帮手!
200字范文 > 设计模式 原则 饿汉式单例模式 抽象工厂 代理模式 观察者模式 模板方法模式使用场景

设计模式 原则 饿汉式单例模式 抽象工厂 代理模式 观察者模式 模板方法模式使用场景

时间:2022-06-20 17:12:38

相关推荐

设计模式 原则 饿汉式单例模式 抽象工厂 代理模式 观察者模式 模板方法模式使用场景

设计模式

​ 对各种面向对象方法的一种总结。前辈们遇到了好多设计问题,然后利用面向对象解决了。然后他们把解决方案汇总起来,形成了20多种设计模式。它可以有效的帮助我们利用面向对象,来提高代码的复用性、扩展性等。

设计模式4个关键元素

模式名称:就是设计模式的名字。问题:就是当面对什么样的设计问题时,应该采用该设计模式。即该设计模式的应用场景解决方案:该设计模式是使用什么样的方案解决的。效果:最后解决后,效果怎么样。比如扩展性怎么样,复用性怎么样。优缺点等等

设计原则

开闭原则

​ 对扩展开放,对修改关闭。就是如果要修改原有的功能或者是扩展功能,尽量去扩展原有的代码,而不是修改原来已有的代码。

里氏替换原则(Liskov Substitution Principle)

​ 任何子类对象都应该可以替换其派生的超类对象 。即,子类可以扩展父类的功能,但不要修改父类原有的功能。 也就是说,当一个子类继承父类后,尽量不要去重写它原有的方法。

依赖转置(依赖倒置)原则

​ 要面向接口编程,不要面向实现编程。两个模块交互时,都访问各自接口,而不是具体的实现类。

单一职责原则

​ 一个对象要专注于一种事情,不要让它担任太多责任。

接口隔离原则

​ 一个接口尽量只包含用户关心的内容。就是一个接口不要太庞大。

迪米特法则

​ 如果两个软件实体之间不是特别必要,尽量不要让他们直接通信。而是找个第三方进行转发,比如使用MQ(消息队列)。

合成复用原则

​ 如果在“组合/聚合”和“继承”之间做抉择时,优先选择“组合/聚合”。

设计模式的分类

创建型模式:单例模式、原型模型、工厂模式、建造者模式

​ 用于创建对象的设计模式。一般可以简化用户创建对象的过程。其次可以降低耦合度,用户不需要关心对象具体的创建过程。

结构型模式:代理模式、适配器模式、桥接模式、装饰器模式

​ 组织对象之间的结构,使其易于扩展等。

行为型模式:模板方法模式、策略模式、状态模式、观察者模式

​ 主要用于决定对象如何做出行为。

创建型模式

单例模式

模式名称:单例,单个实例。整个应用程序只需要一个实例即可。问题:有很多情况下,只需要一个实例即可。现实生活中,地球、中国等,如果创建这些实例,那么只需要一个即可。 在代码世界中,全局上下文、线程池、连接池这些对象,在整个程序中也是只需要一个实例即可。解决方案:禁止用户new该对象。只能通过你提供的静态方法来获取该对象。而你的静态方法返回的都是同一实例。效果:避免用户new多个没用的对象。提高了系统性能

//调用代码Singleton singleton1 = Singleton.getInstance();//单例模式class Singleton {private static Singleton instance = new Singleton();public static Singleton getInstance() {return instance;}}/**懒汉模式,synchronized保证线程安全*重点是懒。系统运行初期并不把该单例对象实例化,而是等第一次使用的时候再进行实例化*/public static synchronized LazySingleton getInstance() {//getInstance 方法前加同步if (instance == null) {instance = new LazySingleton();}return instance;}/**饿汉模式*重点是饿,也就是饥渴。还没到用的时候,就先实例化了,等到用的时候直接就可以用了*/private static final HungrySingleton instance = new HungrySingleton();public static HungrySingleton getInstance() {return instance;}

应用场景

系统中只有一个任务管理器

JDK中的单例:java.lang.Runtime:允许应用程序与运行应用程序的环境进行交互。可以从getRuntime方法获取当前运行时, Runtime.getRuntime().totalMemory() 返回JVM(Java虚拟机)中的总内存量

Spring Bean 作用域

工厂模式

简单工厂模式

模式名称:和生活中的工厂一样,通过工厂来生产产品(对象),而不是自己手动new。问题:把需求给工厂说,然后工厂给你生产,比如我想要黄色的衣服,工厂就给我生产一个黄色的衣服。 在程序中也一样,我通过工厂类,提出我的需求(传递参数),然后工厂类帮我new相应的对象,返回给我。解决方案:定义一个抽象对象(如动物),然后定义一个工厂类,工厂类封装了生产具体动物(当然这些具体动物要继承动物类)的方法。然后你通过参数传递给工厂类,比如要一只汪汪叫的动物,然后工厂方法就会return new Dog()。效果:用户不必关心对象怎么生产的,甚至不用关心这个具体对象是什么。工厂的生产规则可以写入配置文件,这样修改时就不需要动代码了。

class Factory {public static String createProduct(String product) {String result = null;switch (product) {case "Mocca":result = "摩卡";break;case "Latte":result = "拿铁";break;default:result = "其他";break;}return result;}}

工厂方法

抽象工厂

在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。

// 调用方式public class AbstractFactoryTest {public static void main(String[] args) {String result = (new CoffeeFactory()).createProduct("Latte");System.out.println(result); // output:拿铁}}// 抽象工厂abstract class AbstractFactory{public abstract String createProduct(String product);}// 啤酒工厂class BeerFactory extends AbstractFactory{@Overridepublic String createProduct(String product) {String result = null;switch (product) {case "Hans":result = "汉斯";break;case "Yanjing":result = "燕京";break;default:result = "其他啤酒";break;}return result;}}//咖啡工厂class CoffeeFactory extends AbstractFactory{@Overridepublic String createProduct(String product) {String result = null;switch (product) {case "Mocca":result = "摩卡";break;case "Latte":result = "拿铁";break;default:result = "其他咖啡";break;}return result;}}

三者区别

简单工厂:所有的产品都由一个工厂生产。如果你想加产品,就改源代码。工厂方法:有多个工厂,但一个工厂只生产一种产品。如耐克厂只生产耐克鞋,阿迪厂只生产阿迪鞋。如果你想加产品,那就加工厂类。抽象工厂:有多个工厂,每个工厂可以生产多类产品。如耐克厂可以生产耐克鞋和耐克衣服,阿迪厂可以生产阿迪鞋和阿迪衣服。但如果你想生产帽子,那么就需要在抽象工厂里加抽象方法,然后修改所有的子类。

结构型模式

代理模式

模型名称:代理(proxy)。本来该我做的事情,找个代理人替我做。问题:我想把房子租出去,但是又不想直接带人看房,原因有很多:找客户、风险等。所以我找个中介(代理),让他替我把房子租出去。在代码世界中,前端调用一个后台方法,因为风险(要验证其是否登录),我不想让它直接调用核心方法,而是让它调用代理对象,如果没有风险,再由这个代理对象替它调用核心方法。解决方案:新建代理类,在代理类的方法中调用实际方法,可以在实际方法前后增加逻辑。当访问该方法时,不new该方法对应的对象,而是new其代理对象。通常有动态代理和静态代理效果:可以在方法前后增加一些业务逻辑,如日志、安全校验等。

缺点:使用了代理模式,因此程序的性能没有直接调用性能高;使用代理模式提高了代码的复杂度。

三种实现方式

静态代理 继承原有类,重写方法;相当于是多写了一个代理类,在调用的时候调用的是代理类,在代理类中的处理 还是原生的处理逻辑,不过在前后添加上需要添加的代码。缺点:需要为每一个被代理的对象都创建一个代理类。 JDK动态代理,也叫接口代理 Proxy.newProxyInstance(classLoader,interfaces,invocationHandler);通过它创建动态的代理类,我们只需将别的类去调用我们实现的公共方法,就可以。缺点:必须要实现接口。 CGLIB动态代理,子类代理

举例买飞机票

​ 由于离飞机场太远,直接去飞机场买票不太现实,这个时候我们就可以上携程 App 上购买飞机票,这个时候携程 App 就相当于是飞机票的代理商。

//定义售票接口interface IAirTicket {void buy();}//定义飞机场售票class AirTicket implements IAirTicket {@Overridepublic void buy() {System.out.println("买票");}}//代理售票平台class ProxyAirTicket implements IAirTicket {private AirTicket airTicket;public ProxyAirTicket() {airTicket = new AirTicket();}@Overridepublic void buy() {//System.out.println("张三在:"),相当于静态代理airTicket.buy();}}//代理模式调用public class ProxyTest {public static void main(String[] args) {IAirTicket airTicket = new ProxyAirTicket();airTicket.buy();}}

适配器模式

模式名称:在现实世界中,充电器全名为电源适配器。它的作用是将220V的交流电转化为5V的直流电。适配器就是一个转换器,将两种不兼容的东西,通过转换器使其互相兼容。问题:在代码世界中,同样有很多相互之间不兼容的接口或类,它们之间无法直接相互调用,所以就需要适配器来进行转换。解决方案:当用户要给访问目标方法时,就new一个适配器,然后将适配者传给适配器,通过适配器访问目标方法。 比如,用户要给手机充电时,先new一个充电器,然后把手机连上充电器(把手机对象传给充电器),然后充电器访问电源的充电方法。效果:解决了两个对象之间不兼容导致无法调用的问题。

适配器模式可以看作一种“补偿模式”,用来补救设计上的缺陷。应用这种模式算是“无奈之举”。如果在设计初期,我们就能协调规避接口不兼容的问题,那这种模式就没有应用的机会了

行为型模式

模板方法模式

模式名称:拿一个简历模板,把里面内容改改。拷贝别人的代码模板,把里面内容改改。问题:在代码世界,经常会遇到很多逻辑相似的地方,但还不太一样。比如用纯jdbc操作数据库时,要连接数据库、构建Statement、写sql、获取结果、把结果转为对象。虽然都是这个流程,但是每次还都不太一样。如果每次都是复制之前的代码,然后改改,那会出现大量重复的代码。如果后期出现需求变换,比如要改下Statement的实现类,那所有涉及到的地方都要改。解决方案:定义一个模板结构,将具体内容延迟到子类去实现。效果:减少了大量的重复逻辑。

//定义父类abstract class Refrigerator {public void open() {System.out.println("开冰箱门");}//延迟子类去实现public abstract void put();public void close() {System.out.println("关冰箱门");}}//子类放香蕉class Banana extends Refrigerator {@Overridepublic void put() {System.out.println("放香蕉");}}//子类放苹果class Apple extends Refrigerator {@Overridepublic void put() {System.out.println("放苹果");}}//调用模板方法public class TemplateTest {public static void main(String[] args) {Refrigerator refrigerator = new Banana();refrigerator.open();refrigerator.put();refrigerator.close();}}

观察者模式

​ 定义对象之间一对多依赖,让多个观察者对象同时监听一个主题对象, 当一个对象状态改变的时候,所有依赖的对象都会自动收到通知

定义一个抽象目标类Subject,其中包括增加、注销和通知观察者方法

public abstract class Subject {protected List<Observer> observerList = new ArrayList<Observer>();/*** 增加观察者* @param observer 观察者*/public void add(Observer observer) {observerList.add(observer);}/*** 注销观察者,从观察者集合中删除一个观察者* @param observer 观察者*/public void remove(Observer observer) {observerList.remove(observer);}/**通知观察者*/public abstract void notifyObserver();}

对应具体的目标类ConcreteSubject

public class ConcreteSubject extends Subject{@Overridepublic void notifyObserver() {System.out.println("遍历观察者:");for (Observer observer : observerList) {observer.response();}}}

此外需要定义抽象观察者Observer,它一般定义为一个接口,声明一个response()方法,为不同观察者的响应行为定义相同的接口:

public interface Observer {/**声明响应方法*/void response();}

具体的观察者实现:

public class ConcreteObserver1 implements Observer{@Overridepublic void response() {System.out.println("我是具体观察者ConcreteObserver1");}}public class ConcreteObserver2 implements Observer{@Overridepublic void response() {System.out.println("我是具体观察者ConcreteObserver2");}}

最后是客户端测试:

public class Client {public static void main(String[] args) {Subject concreteSubject = new ConcreteSubject();//具体观察者Observer concreteObserver1 = new ConcreteObserver1();Observer concreteObserver2 = new ConcreteObserver2();concreteSubject.add(concreteObserver1);concreteSubject.add(concreteObserver2);concreteSubject.notifyObserver();}}

本内容不代表本网观点和政治立场,如有侵犯你的权益请联系我们处理。
网友评论
网友评论仅供其表达个人看法,并不表明网站立场。