目录
前置概念
🔘什么是设计模式?
设计模式就是把一些重复的问题进行统一的处理,提升代码的可靠性
🔘设计模式的要求
①面向接口编程而不是对实现编程
②优先使用对象组合而不是继承
🔘设计模式的六大原则
①开闭原则:对扩展开放,对修改关闭。即允许对现有的功能扩展但不允许修改之前的内容
②里氏代换原则:任何父类可以出现的地方都允许其子类出现
③依赖倒转原则:针对接口编程,依赖于抽象接口而不依赖于具体
④接口隔离原则:要求多个接口之间保持隔离,是为了降低类之间的耦合度
⑤最少知道原则:一个实体应当减少与其他实体之间发生的相互作用,让多功能模块保持相对独立
⑥合成复用原则:尽量使用合成/聚合的方式,而不是使用继承,换句话来说就是少用继承
设计模式
创建型模式
这种类型的模式提供了一种在创建对象的同时隐藏创建对象的过程,而不是使用new运算符直接实例化对象。
🔘工厂模式
🔘什么是工厂模式(Factory Pattern)
创建对象时不会对客户端暴露创建逻辑,并且是通过使用一个共同的接口来指向新创建的对象.
在明确的计划下,需要在不同的条件下创建不同的对象
优点:①调用者只需要提供条件 ②扩展性极高 ③屏蔽产品的具体实现,开发者只需关心产品的接口
缺点:①每次增加一个产品时,都需要增加一个具体类和对象实现工厂,使得系统中类的个数成倍增加,
在一定程度上增加了系统的复杂度,同时也增加了系统具体类的依赖。
定义一个接口,让所有的类去继承,定义一个工厂类,根据不同的条件创建不同的实现类对象,
从而实现创建对象的过程不再依赖某个具体的实现类而是依赖于工厂类的
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 public interface Shape { void draw () ; } public class Circle implements Shape { @Override public void draw () { System.out.println("绘制了圆形" ); } } public class ShapeFactory { public Shape getShape (String target ) { if (target == null ){ return null ; }else if ("circle" .equalsIgnoreCase(target )){ return new Circle(); }else if ("square" .equalsIgnoreCase(target )){ return new Square(); }else if ("rectangle" .equalsIgnoreCase(target )){ return new Rectangle(); } return null ; } }
抽象工厂模式
1 🔘什么是抽象工厂模式(Abstract Factory Pattern)
该模式围绕一个超级工厂创建其他工厂,这个超级工厂又称为工厂的工厂。
接口是负责创建一个工厂的标准约束,不再指向某个具体实现类。
当某个系统的产品中有多个产品族,而在某个时刻只需要使用其中一个产品
产品族:一个品牌下面的所有产品;例如华为的手机,路由器,电脑 统称为华为的产品族;
优点:当一个产品族中的多个对象被设计成一起工作时,它能保证客户端始终只使用同一个产品族中的对象。
缺点:产品族扩展非常困难,要增加一个系列的某一产品,就违背了开闭原则,既要修改工厂抽象类里加代码,
又修改具体的实现类里面加代码;
单例模式
1 🔘什么是单例模式(Singleton Pattern )
单例模式对单一的类提供了一种创建自己对象的方式,同时确保了只有单个对象被创建。
且这个类还有提供了一张方式去直接访问其唯一的对象,不需要实例化该类的对象。
🔘单例模式的要求
①只能有一个实例
②必须是自己创建自己的唯一实例,即将构造函数私有化
③必须有给其他对象提供访问唯一实例的方式
单例模式的目的
避免一个全局使用的类频繁创建和销毁,保证此类仅有一个实例,并且提供一个访问它的方式
优点是在内存中只有一个实例,减少了内存开销,避免了重复资源的创建
缺点是没有接口,不能被继承,与单一职责原则冲突(一个类应该只关系内部逻辑,而不是外部如何实例化)
是否为懒加载:否
是否多线程安全:是(在类加载时就会自动加载到内存中,在执行业务之前此对象就被创建了)
优点:没有加锁,执行效率高
缺点:类加载时就完成初始化,占用内存空间(无法保证初始化后使用,如果一直不使用,就会浪费内存)
1 2 3 4 5 6 7 8 9 10 11 public class HungrySingleton { //提前先创建好单例对象 private static HungrySingleton instance = new HungrySingleton(); //私有化类的构造器,防止外部new对象 private HungrySingleton(){ } //提供公共的方法访问此单例对象 public static HungrySingleton getSingleInstance(){ return instance; } }
🔘单例模式之懒汉式
是否为懒加载:是
是否多线程安全:否(在多个线程访问时,有可能创建多个对象)
优点:什么时候调用什么时候创建,节省内存空间
缺点:线程不安全,需要通过加锁synchronized来保证单例,但加锁后会影响效率
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class LazySingleton { //创建好单例对象但暂时不进行初始化 private static LazySingleton instance; //私有化类的构造器,防止外部new对象 private LazySingleton(){ } //提供公共的方法访问此单例对象 public static synchronized LazySingleton getSingleInstance(){ if (instance == null){ instance = new LazySingleton(); } return instance; } }
🔘单例模式之双重校验锁
是否为懒加载:是
是否多线程安全:是(通过加锁保证了多线程安全)
优点:双重锁机制,在保证多线程安全的同时保持相对较高的效率,比懒汉式效率更快,缩小了锁的范围
缺点:添加了锁,不可避免效率受到一定的影响
一般通过这种方式用于取代懒汉式
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 public class DCLSingleton { private volatile static DCLSingleton instance; private DCLSingleton () { } public static DCLSingleton getSingleInstance () { if (instance == null ){ synchronized (DCLSingleton.class ){ if (instance == null ){ instance = new DCLSingleton(); } } } return instance; } }
🔘单例模式之登记式(静态内部类)
是否为懒加载:是
因为是在静态内部类中声明了单例对象,在加载一个外部类时,其内部类不会被同时加载。
只有在外部类显式调用或获取内部类属性和方法时,内部类的静态变量,静态方法才会被加载
**(但只是加载,不一定是实例化)**因此间接实现了延迟加载
是否多线程安全:是
通过classloader机制保证了初始化单例对象instance时只有一个线程,因此保证了线程安全问题
1 2 3 4 5 6 7 8 9 10 11 12 13 14 public class RegisterSingleton { private static class SingletonHolder { private static final RegisterSingleton INSTANCE = new RegisterSingleton(); } private RegisterSingleton () {}; public static RegisterSingleton getInstance () { return SingletonHolder.INSTANCE; } }
🔘单例模式之枚举式
是否为懒加载:否(枚举类加载完成该单例对象已存在)
是否多线程安全:是
枚举类最终会被编译为被 final 修饰的普通类,它的所有属性也都会被 static 和 final 关键字修饰,
枚举类在启动时就会被 JVM 加载并初始化,而这个执行过程是线程安全的,所以枚举类也是线程安全的类。
优点:自动支持序列化机制,同时防止了多次实例化
缺点:jdk1.5后才引入enum,因此使用较少
1 2 3 4 5 6 7 8 9 10 11 public enum EnumSingleton { INSTANCE; public void test () { System.out .println("枚举式单例对象获取成功,调用方法成功!" ); } }
建造者模式
🔘什么是建造者模式(Builder Pattern)
使用多个简单的对象一步步构成一个复杂的对象。一个Builder类会一步步构造最终对象,该类是独立于其他对象的
🔘建造者模式的目的
将一个复杂的构建与其最终表示相分离,使得同样的构建过程可以创建不同的表示
🔘建造者模式的优缺点
优点:
①建造者独立,可以很容易扩展新的功能
②便于控制细节风险
缺点:
①产品必须有共同点,范围有所限制
②如果内部变化复杂,就会有很多的建造类
原型模式
🔘什么是原型模式(Prototype Pattern)
该模式用于需要反复创造重复的对象,同时又要保证性能。
该模式是实现了一个原型接口(Cloneable),该接口用于克隆对象
🔘原型模式的优缺点
优点:
①性能得到提高(不需要再反复new对象,而是在指定对象的基础上进行复制)
②避免了构造函数的约束(因为也是在指定对象的基础上进行复制,不需要通过构造函数创建的)
缺点:
①配备克隆方法需要对类的功能进行通盘考虑,对全新的类来说很简单,但对已存在的类就不一定,
特别是当一个类引用不支持序列化的间接对象或者引用含有循环结构的时候。
②必须实现Cloneable接口
🔘使用场景
①类的初始化需要耗费大量资源
②new生成一个对象需要非常繁琐的数据准备和访问权限就可以考察使用原型模式
③一个对象多个修改者时或者一个对象多个修改者且需要保存一份原始数据时
**PS:**与通过对一个类进行实例化来构造新对象不同的是原型模式是通过拷贝一个现有对象生成新的对象。
浅拷贝实现Cloneable接口,重写clone()方法;深拷贝是通过实现Serializable接口读取二进制流。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 public abstract class Shape implements Cloneable { private String id; protected String type ; public String getId ( ) { return id; } public void setId (String id ) { this .id = id; } public String getType ( ) { return type ; } abstract void draw (); public Object clone ( ){ Object clone = null ; try { clone = super .clone (); } catch (CloneNotSupportedException e) { e.printStackTrace (); } return clone; } } public class ShapeCache { private static Hashtable <String ,Shape > hashtable = new Hashtable <>(); public static void load ( ){ Circle circle = new Circle (); circle.setId ("1" ); Square square = new Square (); square.setId ("2" ); Rectangle rectangle = new Rectangle (); rectangle.setId ("3" ); hashtable.put (circle.getId (),circle); hashtable.put (square.getId (), square); hashtable.put (rectangle.getId (),rectangle); } public static Shape cloneByCache (String id ){ Shape shape = hashtable.get (id); return (Shape ) shape.clone (); } }
结构型模式
🔘什么是结构型模式(Structural Patterns)
这种类型模式关注类和对象的组合,继承的概念被用来组合接口和定义组合对象获得新功能的方式
适配器模式
🔘什么是适配器模式(Adapter Pattern)
该模式作为两个不兼容的接口之间的桥梁,起到转换和兼容的作用。
该模式涉及到一个单一的适配器类,该类负责加入独立的或不兼容的接口功能。
🔘优点
①让两个互不关联的类形成一定的关系
②提升了类的复用和透明度
③灵活性得到提升
🔘缺点
①引入过多的类,系统复杂度更高了
②由于JAVA至多继承一个类,所以至多只能适配一个适配者类,而且目标类必须是抽象类。
🔘适配器模式的实现
①类适配器模式(适配器继承被适配的类)
②对象适配器(适配器持有被适配类的实例对象)
③接口适配器(通过抽象适配器实现某个接口,再通过自定义适配器继承抽象适配器,自定义实现接口的某个方法即可)
🔘个人的理解
把一个类的接口变成客户端所期待的另一种接口,使原本接口不兼容的两个类,可以一起工作。
一般逻辑是将自己不兼容的接口,包裹在一个类里面,而该类就是适配器。
简单来说,就是将源角色的api通过适配器,适配为目标角色的api。
适配器模式的角色有三种,分别是被适配接口角色,适配器角色以及目标接口角色。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public class AudioPlayer implements MediaPlayer { private MediaAdapter mediaAdapter; @Override public void play (String audioType, String filename ) { if (audioType.equalsIgnoreCase ("mp3" )){ System .out .println ("正在播放MP3,文件名是:" + filename); }else if (audioType.equalsIgnoreCase ("vlc" ) || audioType.equalsIgnoreCase ("mp4" ) ){ mediaAdapter = new MediaAdapter (audioType); mediaAdapter.play (audioType,filename); }else { System .out .println ("播放类型不对" ); } } } public class MediaAdapter implements MediaPlayer { private AdvanceMediaPlayer advanceMediaPlayer; public MediaAdapter (String audioType){ if ("vlc" .equalsIgnoreCase (audioType)){ advanceMediaPlayer = new VlcPlayer (); }else if ("mp4" .equalsIgnoreCase (audioType)){ advanceMediaPlayer = new Mp4Player (); } } @Override public void play (String audioType, String filename ) { if ("vlc" .equalsIgnoreCase (audioType)){ advanceMediaPlayer.playVlc (filename); }else if ("mp4" .equalsIgnoreCase (audioType)){ advanceMediaPlayer.playMp4 (filename); } } } public class AdapterPatternDemo { public static void main (String [] args ) { AudioPlayer audioPlayer = new AudioPlayer (); audioPlayer.play ("mp3" ,"test" ); } }
桥接模式
🔘什么是桥接模式(Bridge Pattern)
用于把抽象化与实现化解耦,使得二者可以独立变化。
这种模式涉及到一个作为桥接的接口,它通过提供抽象化和实现化之间的桥接结构,来实现二者的解耦。
🔘如何理解桥接模式
桥接模式是有方向性的,桥绑定的一方是被调用者,属于被动方,抽象方属于主动方。通过组合的方式建立
两个类之间联系,而不是继承。通过桥接(接口)将抽象部分和实现部分解耦,桥接是一个接口,实现方实现
这个接口,抽象方在抽象类中调用接口中的方法指向实现方。这样实现方通过实现桥接口进行单方面扩展,而
抽象方通过继承抽象类进行单方面扩展,两者通过桥接口调用,而接口不受双方扩展的影响。
🔘优缺点
优点:
①抽象化和实现化的分离 ②可扩展性强 ③实现细节对客户透明
缺点:
①桥接模式的引入会增加系统的理解与设计难度,由于聚联关联关系建立在抽象层
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 public interface DrawAPI { void drawCircle(int radius,int x,int y); } public class GreenCircle implements DrawAPI { @Override public void drawCircle(int radius, int x, int y) { System.out .println("填充绿色:" + radius + x + y); } } public class RedCircle implements DrawAPI {}public abstract class Shape { public DrawAPI drawAPI; public Shape(DrawAPI drawAPI){ this .drawAPI = drawAPI; } public abstract void draw(); } public class Circle extends Shape { private int radius; private int x; private int y; public Circle(DrawAPI drawAPI, int radius, int x, int y) { super (drawAPI); this .radius = radius; this .x = x; this .y = y; } @Override public void draw() { drawAPI.drawCircle(radius,x,y); } }
过滤器模式
🔘什么是过滤器模式(Filter || Criteria Pattern)
过滤器模式也被称为标准模式,它可以结合了多个标准来获得单一标准。
这种模式允许使用不同的标准来过滤一组对象,通过逻辑运算以解耦的方式把它们连接起来。
🔘优缺点
优点:可以从多个对象中将满足对象保留,不满足对象过滤掉
缺点:冗余代码较多
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 public interface Criteria { List<Person> meetCriteria(List<Person> list); } public class OrCriteria implements Criteria { private Criteria criteria; private Criteria otherCriteria; public OrCriteria(Criteria criteria, Criteria otherCriteria) { this .criteria = criteria; this .otherCriteria = otherCriteria; } @Override public List<Person> meetCriteria(List<Person> list) { List<Person> first = new ArrayList <>(); List<Person> second = new ArrayList <>(); first = criteria.meetCriteria(list); second = otherCriteria.meetCriteria(list); for (Person person : second ) { if (!first.contains(person)){ first.add(person); } } return first; } } public class CriteriaMale implements Criteria { @Override public List<Person> meetCriteria(List<Person> list) { List<Person> people = new ArrayList <>(); for (Person person : list ) { if (person.getGender().equalsIgnoreCase("male" )){ people.add(person); } } return people; } }
组合模式
🔘什么是组合模式(Composite Pattern)
组合模式又叫部分整体模式,是用于把一组相似的对象当作一个单一的对象。
组合模式依据树形结构来组合对象,用来表示部分以及整体层次。
这种模式创建了一个包含自己对象组的类。该类提供了修改相同对象组的方式。
🔘使用场景
当某些需要实现树形结构显示时可以考虑使用,例如文件夹遍历操作,前端下拉列表显示不同级别菜单
🔘优缺点
优点:
①高层模块调用简单
②节点添加自由(例如这个案例中,某个员工被提拔为领导,只需要在其list中添加员工即可,整体结构不受影响)
缺点:
①其叶子和树枝的声明都是实现类,而不是接口,违反了依赖倒置原则。
🔘个人理解
组合模式,就是在一个对象中包含其他对象,这些被包含的对象可能是终点对象(不再包含别的对象),
也有可能是非终点对象(其内部还包含其他对象,或叫组对象),我们将对象称为节点,即一个根节点
包含许多子节点,这些子节点有的不再包含子节点,而有的仍然包含子节点,以此类推。很明显,这是
树形结构,终结点叫叶子节点,非终节点(组节点)叫树枝节点,第一个节点叫根节点。同时也类似于
文件目录的结构形式:文件可称之为终节点,目录可称之为非终节点(组节点)。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public class Employee { private String name; private String dept; private int salary; private ArrayList <Employee > subordinate; public Employee (String name, String dept, int salary) { this .name = name; this .dept = dept; this .salary = salary; this .subordinate = new ArrayList <>(); } public void add (Employee employee ){ this .subordinate .add (employee); } public void remove (Employee employee ){ this .subordinate .remove (employee); } public List <Employee > getSubordinate ( ){ return this .subordinate ; } @Override public String toString ( ) { return "Employee{" + "name='" + name + '\'' + ", dept='" + dept + '\'' + ", salary=" + salary + ", subordinate=" + subordinate + '}' ; } }
装饰器模式
🔘什么是装饰器模式(Decorator Pattern)
即向一个现有对象添加新的功能,同时不能改变该对象的结构
该模式通过创建一个装饰类,用于包装原来的类,并在保持类方法签名完整性的前提下提供新的功能。
关于装饰者模式的辅助理解 –> 装饰者模式
🔘使用场景
当为了扩展某一个类经常需要使用继承方式实现,或者动态增加功能,动态撤销。则可以考虑使用装饰器模式
🔘优缺点:
优点:
①装饰类和被装饰类可以独立发展,不会相互耦合
②装饰模式是继承的一个替代模式,装饰模式可以动态扩展一个实现类的功能。
缺点:
①多层装饰比较复杂。
装饰器模式与桥接模式的区别
①装饰器模式中抽象类是实现了接口并持有接口实例,桥接模式中抽象类以组合的方式持有接口实例,但没实现接口。
②桥接模式是为了实现两个没有关联的维度的东西的自由组合,这里没有关联是指各自拥有自己的属性和方法,
没有相同点(使用聚合或者组合)
③装饰者模式使用了继承必然是两个种类具有相同的一些属性和方法,它不是为了实现两个维度的自由组合,
是为了实现对对象的一层一层又一层包装,调用方法时,每一层包装递归的调用上一层的包装。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 public interface Shape { void draw () ; } public class Circle implements Shape { @Override public void draw () { System.out.println("绘制圆形" ); } } public abstract class ShapeDecorator implements Shape { private Shape shape; public ShapeDecorator (Shape shape) { this .shape = shape; } @Override public void draw () { shape.draw(); } } public class RedShapeDecorator extends ShapeDecorator { public RedShapeDecorator (Shape shape) { super (shape); } @Override public void draw () { super .draw(); setRedColor(); } private void setRedColor () { System.out.println("图形被填充为红色" ); } }
外观模式
🔘什么是外观模式(Facade Pattern)
该模式用于隐藏系统的复杂性,并向客户端提供了一个客户端可以访问系统的接口。
这种模式涉及到一个单一的类,该类提供了客户端请求的简化方法和对现有系统类方法的委托调用。
🔘使用场景:
①为复杂的模块或子系统提供外界访问的模块。②子系统相对独立。 ③预防低水平人员带来的风险。
🔘优缺点
优点:①减少系统相互依赖。 ②提高灵活性。 ③提高了安全性。
缺点:不符合开闭原则,如果要改东西很麻烦,继承重写都不合适。
🔘外观模式与工厂模式的区别
外观模式侧重于对外部调用者提供简化的方法。工厂模式侧重于隐藏对象创建的过程。
虽然两种模式下都是在一个额外的类中去创建子系统的对象。不同之处在于简单工厂模式的output是一个子系统对象。
而外观模式没有对外返回子系统对象。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 public interface Shape { void draw () ; } public class Circle implements Shape { @Override public void draw () { System.out .println("绘制了圆形" ); } } public class ShapeMaker { private Shape circle; private Shape rectangle; private Shape square; public ShapeMaker () { this .circle = new Circle(); this .rectangle = new Rectangle(); this .square = new Square(); } public void drawCircle () { circle.draw(); } public void drawRectangle () { rectangle.draw(); } public void drawSquare () { square.draw(); } }
享元模式
🔘什么是享元模式(Flyweight Pattern)
该模式主要用于减少创建对象的数量,以减少内存占用和提高性能,并改善应用所需的对象结构的方式。
享元模式尝试重用现有的同类对象,如果未找到匹配的对象,则创建新对象。
🔘使用场景
系统中有大量的重复对象、重复对象的创建消耗大量内存
🔘优缺点
优点:减少创建对象的数量,降低系统对内存的使用,使得效率提高
缺点:同时也提高了系统的复杂度,需要分离出外部状态和内部状态,而且外部状态具有固有化的性质,
不应该随着内部状态的变化而变化,否则会造成系统的混乱。
🔘享元模式和原型模式的区别
享元模式是为了在创建新对象的过程中减少已存在对象的创建同时提高性能的目的;
原型模式是为了在已存在的对象基础上创建大量重复对象的同时保持高性能
例如:在有些场景下,我们需要重复创建多个实例,例如在循环体中赋值一个对象,此时我们
就可以采用原型模式来优化对象的创建过程;而在有些场景下,我们则可以避免重复创建多个实例,
通过采用享元模式在内存中共享对象就好了。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 public interface Shape { void draw(); } public class Circle implements Shape { private int x; private int y; private int radius; private String color; public Circle(String color) { this .color = color; } } public class ShapeFactory { private static HashMap<String , Shape> list = new HashMap <>(); public static Shape getShape(String color) { Circle circle = (Circle) list.get (color); if (circle != null ){ return circle; } Circle new Circle = new Circle (color); System.out.println("创建[" + color + "]色圆形成功" ); list.put(color,new Circle ); return new Circle ; } }
代理模式
🔘什么是代理模式(Proxy Pattern)
该模式通过一个类代表另一个类的功能,为其他对象提供一种代理以控制对这个对象的访问
🔘使用场景
想在访问一个类时做一些控制
🔘优缺点
优点:①职责明确 ②扩展性较高
缺点:①增加了中间对象,执行效率有所降低 ②实现代理模式需要额外的工作,有些代理模式较为复杂
代理模式、适配器模式、装饰器模式的区别
①和适配器模式的区别:适配器模式主要改变所考虑对象的接口,而代理模式不能改变所代理类的接口。
②和装饰器模式的区别:装饰器模式为了增强功能,而代理模式是为了加以控制。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 public interface Image { void display (); } public class RealImage implements Image { private String fileName; public RealImage (String fileName){ this .fileName = fileName; LoadFromDisk (this .fileName ); } @Override public void display ( ) { System .out .println ("正在显示图片" ); } private void LoadFromDisk (String fileName){ System .out .println ("从硬盘中加载文件成功!" + fileName); } } public class ProxyImage implements Image { private RealImage realImage; private String fileName; public ProxyImage (String fileName) { this .fileName = fileName; } @Override public void display ( ) { if (realImage == null ){ this .realImage = new RealImage (this .fileName ); } realImage.display (); } }
行为型模式
🔘什么是行为型模式(Behavioral Patterns)
这种类型的模式特别关注对象之间的通信
命令模式
🔘什么是命令模式(Command Pattern)
它是一种数据驱动的设计模式,它属于行为型模式。请求以命令的形式包裹在对象中,并传给调用对象。
调用对象寻找可以处理该命令的合适的对象,并把该命令传给相应的对象,该对象执行命令。
🔘目的
将一个请求封装成一个对象,从而使您可以用不同的请求对客户进行参数化。
🔘优缺点
优点:①降低了系统耦合度 ②新的命令可以很容易添加到系统中去
缺点:使用命令模式可能会导致某些系统有过多的具体命令类
🔘个人理解
命令模式把一个请求或者操作封装到命令对象中,这些请求或者操作的内容包括接收者的信息,然后将
该命令对象交由执行者执行,执行者不需要关心命令的接收人或者命令的具体内容,因为这些信息均被
封装到命令对象中。
空对象模式
🔘什么是空对象模式(Null Object Pattern)
通过一个空对象取代 NULL 对象实例的检查。Null 对象不是检查空值,而是反应一个不做任何动作的关系。
在空对象模式中,我们创建一个指定各种要执行的操作的抽象类和扩展该类的实体类,还创建一个未对该类
做任何实现的空对象类,该空对象类将无缝地使用在需要检查空值的地方。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 public abstract class AbstractCustomer { public String name; public abstract Boolean isNull (); public String getName ( ) { return name; } } public class RealCustomer extends AbstractCustomer { private String name; public RealCustomer (String name) { this .name = name; } @Override public Boolean isNull ( ) { return false ; } @Override public String getName ( ) { return name; } } public class NullCustomer extends AbstractCustomer { private String name; public NullCustomer (String name) { this .name = name; } @Override public Boolean isNull ( ) { return true ; } @Override public String getName ( ) { return "没有定义当前对象" + name; } } public class CustomerFactory { private static final String [] names = {"tom" ,"jack" ,"mark" }; public static AbstractCustomer getCustomer (String name ){ for (int i = 0 ; i < names.length ; i++) { if (names[i].equalsIgnoreCase (name)){ return new RealCustomer (name); } } return new NullCustomer (name); } }
策略模式
🔘什么是策略模式(Strategy Pattern)
该模式表示一个类的行为或其算法可以在运行时更改。在策略模式中,我们创建表示各种策略的对象
和一个行为随着策略对象改变而改变的 context 对象。策略对象改变 context 对象的执行算法。
🔘使用场景
一个系统有许多许多类,而区分它们的只是他们直接的行为。
🔘优缺点
优点:①策略的算法可以自由切换 ②避免多个多重条件判断 ③扩展性很高
缺点:①策略类会增多 ②所有的策略类都需要对外暴露
🔘策略模式、装饰器模式、桥接模式的区别
①与装饰器模式的区别:两者都持有了接口的实例,但是对接口的处理,装饰器模式是实现了接口,
策略模式是以聚合、组合的方法。装饰器模式为了动态增强功能而出现,策略模式是通过策略对象的
改变从而影响算法的不同执行方法
②与桥接模式的区别:桥接模式的抽象化和实现化部分都可以自由变化,桥接接口仅仅是提供两者之间
的联系;而在策略模式中,并不考虑Context的变化,只考虑作为策略接口的实例变化对Context的影响
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 public interface Strategy { int do Operation(int num1 ,int num2 ) ; } public class OperationAdd implements Strategy{ @Override public int do Operation(int num1 , int num2 ) { return num1 + num2; } } public class Context { private Strategy strategy; public Context(Strategy strategy ) { this.strategy = strategy; } public int executeStrategy(int num1 ,int num2 ) { return strategy.do Operation(num1 ,num2 ) ; } }
模板模式
🔘什么是模板模式(Template Pattern)
该模式用一个抽象类公开定义了执行它的方法的方式/模板。
它的子类可以按需要重写方法实现,但调用将以抽象类中定义的方式进行。
🔘使用场景
①有多个子类共有的方法,且逻辑相同。 ②重要的、复杂的方法,可以考虑作为模板方法。
🔘优缺点
优点:①封装不变部分,扩展可变部分 ②提取公共代码,便于维护 ③行为由父类控制,子类实现
缺点:每一个不同的实现都需要一个子类来实现,导致类的个数增加,使得系统更加庞大。
🔘个人理解
将方法作为模板,但是由于作为模板的方法不应该有具体的实现逻辑,不然就成为了固定结构,
也就不能称之为模板,因此需要将模板方法内的具体实现置为多个抽象方法,让其子类来定义具体的逻辑。
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 public abstract class Game { public abstract void initialize () ; public abstract void startPlay () ; public abstract void endPlay () ; public final void play () { initialize(); startPlay(); endPlay(); } } public class FootBall extends Game { @Override public void initialize () { System.out .println("足球游戏初始化" ); } @Override public void startPlay () { System.out .println("足球游戏初始化" ); } @Override public void endPlay () { System.out .println("足球游戏初始化" ); } }
待补充:
责任链模式(Chain of Responsibty Pattern)
解释器模式(Interpreter Pattern)
迭代器模式(Iterator Pattern)
中介者模式(Mediator Pattern)
备忘录模式(Memento Pattern)
观察者模式(Observer Pattern)