筹划模式——简单工厂模子、工厂模式、抽象工厂模式、单例模式、代理模式、 [复制链接]
发表于 2024-11-25 15:29:19 | 显示全部楼层 |阅读模式

马上注册,结交更多好友,享用更多功能,让你轻松玩转社区。

您需要 登录 才可以下载或查看,没有账号?立即注册

×
筹划模式



  • 面向接口编程,而不是面向实现。这个很重要,也是优雅的、可扩展的代码的第一步。
  • 职责单一原则。每个类都应该只有一个单一的功能,并且该功能应该由这个类完全封装起来。
  • 对修改关闭,对扩展开放。对修改关闭是说,我们写出来的代码,该实现的功能和该修复的 bug 都完成了,别人可不能说改就改;对扩展开放就比较好明白了,也就是说在写好的代码基础上,很轻易实现扩展。
创建型模式比较简单,但是会比较没故意思,结构型和活动型比较故意思
每个代理模式的代码都必须本技艺动完成一遍。
创建型模式

创建型模式的作用就是创建对象,说到创建一个对象,最认识的就是 new 一个对象,然后 set 相关属性。但是,在许多场景下,我们需要给客户端提供更加友好的创建对象的方式,尤其是那种我们定义了类,但是需要提供给其他开辟者用的时候。
工厂模式分为简单工厂模式,工厂模式,抽象工厂模式
在工厂模式中,我们在创建对象时不会对客户端袒露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象。本质就是使用工厂方法代替new操作。
简单工厂模式

  1. public class FoodFactory {
  2.     public static Food makeFood(String name) {
  3.         if (name.equals("兰州拉面")) {
  4.             Food noodle = new LanZhouNoodle();
  5.             System.out.println("兰州拉面"+noodle+"出锅啦");
  6.             return noodle;
  7.         } else if (name.equals("黄焖鸡")) {
  8.             Food chicken = new HuangMenChicken();
  9.             System.out.println("黄焖鸡"+ chicken +"出锅啦");
  10.             return chicken;
  11.         } else {
  12.             System.out.println("不知道你做的什么哦~");
  13.             return null;
  14.         }
  15.     }
  16. }
复制代码
此中,LanZhouNoodle 和 HuangMenChicken 都继续自 Food。
  1. public class Cook {
  2.     public static void main(String[] args) {
  3.         Food food = FoodFactory.makeFood("黄焖鸡");
  4.         FoodFactory.makeFood("jaja");
  5.     }
  6. }
复制代码
简单地说,简单工厂模式通常就是如许,一个工厂类 XxxFactory,内里有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。
   我们强调职责单一原则,一个类只提供一种功能,FoodFactory 的功能就是只要负责生产各种 Food。
  在此例中可以看出,Cook 类在使用 FoodFactory 时就不需要 new 任何一个对象,这就是简单工厂模式的好处,封装了 new 的部分,做到的代码易用性。
工厂模式

简单工厂模式很简单,假如它能满足我们的需要,我以为就不要折腾了。之所以需要引入工厂模式,是因为我们往往需要使用两个或两个以上的工厂。
  1. public interface FoodFactory {
  2.     Food makeFood(String name);
  3. }
  4. public class ChineseFoodFactory implements FoodFactory {
  5.     @Override
  6.     public Food makeFood(String name) {
  7.         if (name.equals("A")) {
  8.             return new ChineseFoodA();
  9.         } else if (name.equals("B")) {
  10.             return new ChineseFoodB();
  11.         } else {
  12.             return null;
  13.         }
  14.     }
  15. }
  16. public class AmericanFoodFactory implements FoodFactory {
  17.     @Override
  18.     public Food makeFood(String name) {
  19.         if (name.equals("A")) {
  20.             return new AmericanFoodA();
  21.         } else if (name.equals("B")) {
  22.             return new AmericanFoodB();
  23.         } else {
  24.             return null;
  25.         }
  26.     }
  27. }
复制代码
此中,ChineseFoodA、ChineseFoodB、AmericanFoodA、AmericanFoodB 都派生自 Food。
客户端调用:
  1. public class APP {
  2.     public static void main(String[] args) {
  3.         // 先选择一个具体的工厂
  4.         FoodFactory factory = new ChineseFoodFactory();
  5.         // 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
  6.         Food food = factory.makeFood("A");
  7.     }
  8. }
复制代码
固然都是调用 makeFood(“A”) 制作 A 类食品,但是,不同的工厂生产出来的完全不一样。
第一步,我们需要选取符合的工厂,然后第二步根本上和简单工厂一样。
焦点在于,我们需要在第一步选好我们需要的工厂。好比,我们有 LogFactory 接口,实现类有 FileLogFactory 和 KafkaLogFactory,分别对应将日志日志写入文件和写入 Kafka 中,显然,我们客户端第一步就需要决定到底要实例化 FileLogFactory 还是 KafkaLogFactory,这将决定之后的全部的操作。
抽象工厂模式

当涉及到产品族的时候,就需要引入抽象工厂模式了。 一个经典的例子是造一台电脑 。
当涉及到这种产品族的问题的时候,就需要抽象工厂模式来支持了。我们不再定义 CPU 工厂、主板工厂、硬盘工厂、显示屏工厂等等,我们直接定义电脑工厂,每个电脑工厂负责生产全部的设备,如许能包管肯定不存在兼容问题。
当然,抽象工厂的问题也是显而易见的,好比我们要加个显示器,就需要修改全部的工厂,给全部的工厂都加上制造显示器的方法。这有点违反了对修改关闭,对扩展开放这个筹划原则。
本节要先容的抽象工厂模式将考虑多等级产品的生产,将同一个详细工厂所生产的位于不同等级的一组产品称为一个产品族,图 1 所示的是海尔工厂和 TCL 工厂所生产的电视机与空调对应的关系图。
抽象工厂(AbstractFactory)模式的定义:是一种为访问类提供一个创建一组相关或相互依靠对象的接口,且访问类无须指定所要产品的详细类就能得到同族的不同等级的产品的模式结构。
抽象工厂模式是工厂方法模式的升级版本,工厂方法模式只生产一个等级的产品,而抽象工厂模式可生产多个等级的产品。
使用抽象工厂模式一样平常要满足以下条件。


  • 系统中有多个产品族,每个详细工厂创建同一族但属于不同等级结构的产品。
  • 系统一次只可能消耗此中某一族产品,即同族的产品一起使用。
抽象工厂模式除了具有工厂方法模式的优点外,其他重要优点如下。


  • 可以在类的内部对产品族中相关联的多等级产品共同管理,而不必专门引入多个新的类来举行管理。
  • 当增长一个新的产品族时不需要修改原代码,满足开闭原则。
其缺点是:当产品族中需要增长一个新的产品时,全部的工厂类都需要举行修改。
单例模式

简单点说,就是一个应用步调中,某个类的实例对象只有一个,你没有办法去new,因为构造器是被private修饰的,一样平常通过getInstance()的方法来获取它们的实例。
getInstance()的返回值是一个对象的引用,并不是一个新的实例,所以不要错误的明白成多个对象。
特点


  • 类构造器私有
  • 持有自己类型的属性
  • 对外提供获取实例的静态方法
饿汉式写法
  1. public class Singleton {  
  2.    private static Singleton instance = new Singleton();  
  3.    private Singleton (){}  
  4.    public static Singleton getInstance() {  
  5.    return instance;  
  6.    }  
  7. }
复制代码
弊端:因为类加载的时候就会创建对象,所以有的时候还不需要使用对象,就会创建对象,造成内存的浪费;
饱汉模式最轻易堕落:
  1. public class Singleton {
  2.     // 首先,也是先堵死 new Singleton() 这条路
  3.     private Singleton() {}
  4.     // 和饿汉模式相比,这边不需要先实例化出来,注意这里的 volatile,它是必须的
  5.     private static volatile Singleton instance = null;
  6.     public static Singleton getInstance() {
  7.         if (instance == null) {
  8.             // 加锁
  9.             synchronized (Singleton.class) {
  10.                 // 这一次判断也是必须的,不然会有并发问题
  11.                 if (instance == null) {
  12.                     instance = new Singleton();
  13.                 }
  14.             }
  15.         }
  16.         return instance;
  17.     }
  18. }
复制代码
  双重检查,指的是两次检查 instance 是否为 null。
  volatile 在这里是需要的,渴望能引起读者的关注。
  许多人不知道怎么写,直接就在 getInstance() 方法签名上加上 synchronized,这就不多说了,性能太差。
  嵌套类最经典,以后大家就用它吧:
  1. public class Singleton {
  2.     private Singleton() {}
  3.     // 主要是使用了 嵌套类可以访问外部类的静态属性和静态方法 的特性
  4.     private static class Holder {
  5.         private static Singleton instance = new Singleton();
  6.     }
  7.     public static Singleton getInstance() {
  8.         return Holder.instance;
  9.     }
  10. }
复制代码
  留意,许多人都会把这个嵌套类说成是静态内部类,严格地说,内部类和嵌套类是不一样的,它们能访问的外部类权限也是不一样的。
  最后,我们说一下罗列,罗列很特别,它在类加载的时候会初始化内里的全部的实例,而且 JVM 包管了它们不会再被实例化,所以它天生就是单例的。
TODO:
建造者模式
原型模式
结构型模式

前面创建型模式先容了创建对象的一些筹划模式,这节先容的结构型模式旨在通过改变代码结构来到达解耦的目的,使得我们的代码轻易维护和扩展。
代理模式

第一个要先容的代理模式是最常使用的模式之一了,用一个代理来隐藏详细实现类的实现细节,通常还用于在真实的实现的前后添加一部分逻辑。
既然说是代理,那就要对客户端隐藏真实实现,由代理来负责客户端的全部请求。当然,代理只是个代理,它不会完成现实的业务逻辑,而是一层皮而已,但是对于客户端来说,它必须表现得就是客户端需要的真实实现。
明白代理这个词,这个模式着实就简单了。 下面上代码明白。 代理接口:
  1. //要有一个代理接口让实现类和代理实现类来实现。
  2. public interface FoodService {
  3.     Food makeChicken();
  4. }
复制代码
被代理的实现类:
  1. public class FoodServiceImpl implements FoodService {
  2.     @Override
  3.     public Food makeChicken() {
  4.         Food f = new Chicken();
  5.         f.setChicken("1kg");
  6.         f.setSpicy("1g");
  7.         f.setSalt("3g");
  8.         System.out.println("鸡肉加好佐料了");
  9.         return f;
  10.     }
  11. }
复制代码
被代理实现类就只需要做自己该做的事情就好了,不需要管别的。
代理实现类:
  1. public class FoodServiceProxy implements FoodService {
  2.     // 内部一定要有一个真实的实现类,当然也可以通过构造方法注入
  3.     private FoodService foodService = new FoodServiceImpl();
  4.    
  5.     @Override
  6.     public Food makeChicken() {
  7.         System.out.println("开始制作鸡肉");
  8.         
  9.         // 如果我们定义这句为核心代码的话,那么,核心代码是真实实现类做的,
  10.         // 代理只是在核心代码前后做些“无足轻重”的事情
  11.         Food food = foodService.makeChicken();
  12.         
  13.         System.out.println("鸡肉制作完成啦,加点胡椒粉");
  14.         food.addCondiment("pepper");
  15.         System.out.println("上锅咯");
  16.         return food;
  17.     }
  18. }
复制代码
客户端调用,留意,我们要用代理来实例化接口:
  1. // 这里用代理类来实例化
  2. FoodService foodService = new FoodServiceProxy();
  3. foodService.makeChicken();
复制代码
所谓代理模式,就是对被代理方法包装大概叫加强, 在面向切面编程(AOP)中,着实就是动态代理的过程。好比 Spring 中,我们自己不定义代理类,但是 Spring 会帮我们动态来定义代理,然后把我们定义在 @Before、@After、@Around 中的代码逻辑动态添加到代理中。
待续。。。
活动型模式

模板模式

在含有继续结构的代码中,模板方法模式是非常常用的。
父类定义了骨架(调用哪些方法及序次),某些特定方法由子类实现
模板方法只负责定义第一步应该要做什么,第二步应该做什么,第三步应该做什么,至于怎么做,由子类来实现。
好处:代码复用,减少重复代码。除了子类要实现的特定方法,其他方法及方法调用序次都在父类中预先写好
缺点: 每一个不同的实现都需要一个子类来实现,导致类个数增长,使系统更加庞大
模板模式的关键点:
1、使用抽象类定义模板类,并在此中定义全部的根本方法、模板方法,钩子方法,不限数量,以实现功能逻辑为主。此中根本方法使用final修饰,此中要调用根本方法和钩子方法,根本方法和钩子方法可以使用protected修饰,表明可被子类修改。
2、定义实现抽象类的子类,重写此中的模板方法,甚至钩子方法,完善详细的逻辑。
使用场景:
1、在多个子类中拥有相同的方法,而且逻辑相同时,可以将这些方法抽出来放到一个模板抽象类中。
2、步调主框架相同,细节不同的情况下,也可以使用模板方法。
架构方法先容

模板方法使得子类可以在不改变算法结构的情况下,重新定义算法中的某些步调。其重要分为两大类:模版方法和根本方法,而根本方法又分为:抽象方法(Abstract Method),详细方法(Concrete Method),钩子方法(Hook Method)。
四种方法的根本定义(前提:在抽象类中定义):
(1)抽象方法:由抽象类声明,由详细子类实现,并以abstract关键字举行标识。
(2)详细方法:由抽象类声明并且实现,子类并不实现大概做覆盖操作。着实质就是普遍适用的方法,不需要子类来实现。
(3)钩子方法:由抽象类声明并且实现,子类也可以选择加以扩展。通常抽象类会给出一个空的钩子方法,也就是没有实现的扩展。它和详细方法在代码上没有区别,不过是一种意识的区别;而它和抽象方法偶然候也是没有区别的,就是在子类都需要将着实现的时候。而不同的是抽象方法必须实现,而钩子方法可以不实现。也就是说钩子方法为你在实现某一个抽象类的时候提供了可选项,相当于预先提供了一个默认设置。
(4)模板方法:定义了一个方法,此中定义了整个逻辑的根本骨架。
  1. public abstract class AbstractTemplate {
  2.     // 这就是模板方法
  3.     public void templateMethod() {
  4.         init();
  5.         apply(); // 这个是重点
  6.         end(); // 可以作为钩子方法
  7.     }
  8.         //这是具体方法
  9.     protected void init() {
  10.         System.out.println("init 抽象层已经实现,子类也可以选择覆写");
  11.     }
  12.     // 这是抽象方法,留给子类实现
  13.     protected abstract void apply();
  14.         //这是钩子方法,可定义一个默认操作,或者为空
  15.     protected void end() {
  16.     }
  17. }
复制代码
免责声明:如果侵犯了您的权益,请联系站长,我们会及时删除侵权内容,谢谢合作!更多信息从访问主页:qidao123.com:ToB企服之家,中国第一个企服评测及商务社交产业平台。
回复

使用道具 举报

登录后关闭弹窗

登录参与点评抽奖  加入IT实名职场社区
去登录
快速回复 返回顶部 返回列表