创建型
1.单例模式
在单例模式的实现过程中,需要注意如下三点:
单例类的构造函数为私有;
提供一个自身的静态私有成员变量;
提供一个公有的静态工厂方法
优点:
- 提供了对唯一实例的受控访问。因为单例类封装了它的唯一实例,所以它可以严格控制客户怎样以及何时访问它,并为设计及开发团队提供了共享的概念。
- 由于在系统内存中只存在一个对象,因此可以节约系统资源,对于一些需要频繁创建和销毁的对象,单例模式无疑可以提高系统的性能。
- 允许可变数目的实例。我们可以基于单例模式进行扩展,使用与单例控制相似的方法来获得指定个数的对象实例。
缺点: - 由于单例模式中没有抽象层,因此单例类的扩展有很大的困难。
- 单例类的职责过重,在一定程度上违背了“单一职责原则”。因为单例类既充当了工厂角色,提供了工厂方法,同时又充当了产品角色,包含一些业务方法,将产品的创建和产品的本身的功能融合到一起。
- 滥用单例将带来一些负面问题,如为了节省资源将数据库连接池对象设计为单例类,可能会导致共享连接池对象的程序过多而出现连接池溢出;现在很多面向对象语言(如Java、C#)的运行环境都提供了自动垃圾回收的技术,因此,如果实例化的对象长时间不被利用,系统会认为它是垃圾,会自动销毁并回收资源,下次利用时又将重新实例化,这将导致对象状态的丢失。
a.饿汉式单例模式1
2
3
4
5
6
7
8
9
10
11
12public class Hungry {
//构造方法私有
private Hungry() {
}
// 一创建该类就直接new
private static final Hungry HUNGRY=new Hungry();
public static Hungry getInstance() {
return HUNGRY;
}
}
b.懒汉式的单例模式1
2
3
4
5
6
7
8
9
10
11
12
13public class Lazy {
private Lazy() {
}
private static Lazy lazy;
public static Lazy getLazy() {
if(lazy==null) {
lazy = new Lazy();
}
return lazy;
}
}
c.DCL安全的懒汉单例模式1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23//DCL懒汉单例模式,还是会被反射破坏,只有枚举不会
public class LazySafty {
private LazySafty() {
}
// 解决指令重排问题
private volatile static LazySafty lazySafty;
//双重检测锁模式,解决并发问题
public static LazySafty getLazySafty() {
if(lazySafty == null) {
synchronized (LazySafty.class){
if(lazySafty == null) {
lazySafty = new LazySafty();
}
}
}
return lazySafty;
}
}
2.工厂模式
a.简单工厂模式(静态工厂模式)
简单工厂模式(Simple Factory Pattern):又称为静态工厂方法(Static Factory Method)模式,它属于类创建型模式。在简单工厂模式中,可以根据参数的不同返回不同类的实例。简单工厂模式专门定义一个类来负责创建其他类的实例,被创建的实例通常都具有共同的父类。
1.将对象的创建和对象本身业务处理分离可以降低系统的耦合度,使得两者修改起来都相对容易。
2.在调用工厂类的工厂方法时,由于工厂方法是静态方法,使用起来很方便,可通过类名直接调用,而且只需要传入一个简单的参数即可,在实际开发中,还可以在调用时将所传入的参数保存在XML等格式的配置文件中,修改参数时无须修改任何Java源代码。
3.简单工厂模式最大的问题在于工厂类的职责相对过重,增加新的产品需要修改工厂类的判断逻辑,这一点与开闭原则是相违背的。
4.简单工厂模式的要点在于:当你需要什么,只需要传入一个正确的参数,就可以获取你所需要的对象,而无须知道其创建细节。
优点:
- 工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象。
- 客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量。
- 通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性
缺点: - 由于工厂类集中了所有产品创建逻辑,一旦不能正常工作,整个系统都要受到影响。
- 使用简单工厂模式将会增加系统中类的个数,在一定程序上增加了系统的复杂度和理解难度。
- 系统扩展困难,一旦添加新产品就不得不修改工厂逻辑,在产品类型较多时,有可能造成工厂逻辑过于复杂,不利于系统的扩展和维护。
- 简单工厂模式由于使用了静态工厂方法,造成工厂角色无法形成基于继承的等级结构。
1 | public abstract class Pay { |
b.工厂方法模式
工厂方法模式(Factory Method Pattern)又称为工厂模式,也叫虚拟构造器(Virtual Constructor)模式或者多态工厂(Polymorphic Factory)模式,它属于类创建型模式。在工厂方法模式中,工厂父类负责定义创建产品对象的公共接口,而工厂子类则负责生成具体的产品对象,这样做的目的是将产品类的实例化操作延迟到工厂子类中完成,即通过工厂子类来确定究竟应该实例化哪一个具体产品类。
工厂方法模式包含如下角色:
Product:抽象产品
ConcreteProduct:具体产品
Factory:抽象工厂
ConcreteFactory:具体工厂
工厂方法模式是简单工厂模式的进一步抽象和推广。由于使用了面向对象的多态性,工厂方法模式保持了简单工厂模式的优点,而且克服了它的缺点。在工厂方法模式中,核心的工厂类不再负责所有产品的创建,而是将具体创建工作交给子类去做。这个核心类仅仅负责给出具体工厂必须实现的接口,而不负责哪一个产品类被实例化这种细节,这使得工厂方法模式可以允许系统在不修改工厂角色的情况下引进新产品。
优点:
- 在工厂方法模式中,工厂方法用来创建客户所需要的产品,同时还向客户隐藏了哪种具体产品类将被实例化这一细节,用户只需要关心所需产品对应的工厂,无须关心创建细节,甚至无须知道具体产品类的类名。
- 基于工厂角色和产品角色的多态性设计是工厂方法模式的关键。它能够使工厂可以自主确定创建何种产品对象,而如何创建这个对象的细节则完全封装在具体工厂内部。工厂方法模式之所以又被称为多态工厂模式,是因为所有的具体工厂类都具有同一抽象父类。
- 使用工厂方法模式的另一个优点是在系统中加入新产品时,无须修改抽象工厂和抽象产品提供的接口,无须修改客户端,也无须修改其他的具体工厂和具体产品,而只要添加一个具体工厂和具体产品就可以了。这样,系统的可扩展性也就变得非常好,完全符合“开闭原则”。
缺点:
- 在添加新产品时,需要编写新的具体产品类,而且还要提供与之对应的具体工厂类,系统中类的个数将成对增加,在一定程度上增加了系统的复杂度,有更多的类需要编译和运行,会给系统带来一些额外的开销。
- 由于考虑到系统的可扩展性,需要引入抽象层,在客户端代码中均使用抽象层进行定义,增加了系统的抽象性和理解难度,且在实现时可能需要用到DOM、反射等技术,增加了系统的实现难度。
不同的车实现同一个总的车接口,不同的车的制造工厂有相同的总的车工厂,具体车子实现接口,工厂实习工厂接口,去造车。新增只需要写车和车工厂的实习类即可。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
30public abstract class Car {
abstract void getName();
}
public abstract CarFactory {
abstract Car getCar();
}
public class AoDiFactory extends CarFactory {
public Car getCar() {
return new AoDi();
}
}
public class AoDi extends Car {
public void getName() {
System.out.println("aodi");
}
}
public class Test{
psvm{
CarFactory carFactory;
Car car;
carFactory = new Aodi();
car=carFactory.getCar();
car.getName();
}
}
新增只需要新增工厂和对应类
Java反射(Java Reflection):
是指在程序运行时获取已知名称的类或已有对象的相关信息的一种机制,包括类的方法、属性、超类等信息,还包括实例的创建和实例类型的判断等。可通过Class类的forName()方法返回与带有给定字符串名的类或接口相关联的Class对象,再通过newInstance()方法创建此对象所表示的类的一个新实例,即通过一个类名字符串得到类的实例。1
2
3
4//创建一个字符串类型的对象
Class c = Class.forName(“String”);
Object obj = c.newInstance();
return obj;
c.抽象工厂模式
抽象工厂模式(Abstract Factory Pattern):提供一个创建一系列相关或相互依赖对象的接口,而无须指定它们具体的类。抽象工厂模式又称为Kit模式,属于对象创建型模式。
在工厂方法模式中具体工厂负责生产具体的产品,每一个具体工厂对应一种具体产品,工厂方法也具有唯一性,一般情况下,一个具体工厂中只有一个工厂方法或者一组重载的工厂方法。但是有时
候我们需要一个工厂可以提供多个产品对象,而不是单一的产品对象。
为了更清晰地理解工厂方法模式,需要先引入两个概念:
产品等级结构:产品等级结构即产品的继承结构,如一个抽象类是电视机,其子类有海尔电视机、海信电视机、TCL电视机,则抽象电视机与具体品牌的电视机之间构成了一个产品等级结构,抽象电视机是父类,而具体品牌的电视机是其子类。
产品族:在抽象工厂模式中,产品族是指由同一个工厂生产的,位于不同产品等级结构中的一组产品,如海尔电器工厂生产的海尔电视机、海尔电冰箱,海尔电视机位于电视机产品等级结构中,海尔电冰箱位于电冰箱产品等级结构中。
模式动机
- 当系统所提供的工厂所需生产的具体产品并不是一个简单的对象,而是多个位于不同产品等级结构中属于不同类型的具体产品时需要使用抽象工厂模式。
- 抽象工厂模式是所有形式的工厂模式中最为抽象和最具一般性的一种形态。
- 抽象工厂模式与工厂方法模式最大的区别在于,工厂方法模式针对的是一个产品等级结构,而抽象工厂模式则需要面对多个产品等级结构,一个工厂等级结构可以负责多个不同产品等级结构中的产品对象的创建 。当一个工厂等级结构可以创建出分属于不同产品等级结构的一个产品族中的所有对象时,抽象工厂模式比工厂方法模式更为简单、有效率。
优点:
- 抽象工厂模式隔离了具体类的生成,使得客户并不需要知道什么被创建。由于这种隔离,更换一个具体工厂就变得相对容易。所有的具体工厂都实现了抽象工厂中定义的那些公共接口,因此只需改变具体工厂的实例,就可以在某种程度上改变整个软件系统的行为。另外,应用抽象工厂模式可以实现高内聚低耦合的设计目的,因此抽象工厂模式得到了广泛的应用。
- 当一个产品族中的多个对象被设计成一起工作时,它能够保证客户端始终只使用同一个产品族中的对象。这对一些需要根据当前环境来决定其行为的软件系统来说,是一种非常实用的设计模式。
增加新的具体工厂和产品族很方便,无须修改已有系统,符合“开闭原则”。
缺点:
- 在添加新的产品对象时,难以扩展抽象工厂来生产新种类的产品,这是因为在抽象工厂角色中规定了所有可能被创建的产品集合,要支持新种类的产品就意味着要对该接口进行扩展,而这将涉及到对抽象工厂角色及其所有子类的修改,显然会带来较大的不便。
- 开闭原则的倾斜性(增加新的工厂和产品族容易,增加新的产品等级结构麻烦)
模式适用环境
在以下情况下可以使用抽象工厂模式:
1.一个系统不应当依赖于产品类实例如何被创建、组合和表达的细节,这对于所有类型的工厂模式都是重要的。
2.系统中有多于一个的产品族,而每次只使用其中某一产品族。
3.属于同一个产品族的产品将在一起使用,这一约束必须在系统的设计中体现出来。
4.系统提供一个产品类的库,所有的产品以同样的接口出现,从而使客户端不依赖于具体实现。
模式应用:
(1) Java SE AWT(抽象窗口工具包)
在Java语言的AWT(抽象窗口工具包)中就使用了抽象工厂模式,它使用抽象工厂模式来实现在不同的操作系统中应用程序呈现与所在操作系统一致的外观界面。
(2) 在很多软件系统中需要更换界面主题,要求界面中的按钮、文本框、背景色等一起发生改变时,可以使用抽象工厂模式进行设计。
模式扩展
1.“开闭原则”的倾斜性
“开闭原则”要求系统对扩展开放,对修改封闭,通过扩展达到增强其功能的目的。对于涉及到多个产品族与多个产品等级结构的系统,其功能增强包括两方面:
(1) 增加产品族:对于增加新的产品族,工厂方法模式很好的支持了“开闭原则”,对于新增加的产品族,只需要对应增加一个新的具体工厂即可,对已有代码无须做任何修改。
(2) 增加新的产品等级结构:对于增加新的产品等级结构,需要修改所有的工厂角色,包括抽象工厂类,在所有的工厂类中都需要增加生产新产品的方法,不能很好地支持“开闭原则”。
抽象工厂模式的这种性质称为“开闭原则”的倾斜性,抽象工厂模式以一种倾斜的方式支持增加新的产品,它为新产品族的增加提供方便,但不能为新的产品等级结构的增加提供这样的方便。
2.工厂模式的退化
当抽象工厂模式中每一个具体工厂类只创建一个产品对象,也就是只存在一个产品等级结构时,抽象工厂模式退化成工厂方法模式;当工厂方法模式中抽象工厂与具体工厂合并,提供一个统一的工厂来创建产品对象,并将创建对象的工厂方法设计为静态方法时,工厂方法模式退化成简单工厂模式。
有一个总的抽象工厂,用来生产产品:比如Phone和APP,对于Phone和APP而言,不同公司的工厂都可以实现不同牌子的Phone和APP,而对于不同牌子的Phone和APP而言,只需要一个相同产品的接口即可,以至于不同牌子的Phone和APP都去实现相应的产品接口,产品接口只做对应的产品,最终,通过一家公司的工厂,实现抽象接口,对里面的方法进行实现,通过对应实现产品接口的实现类进行实现。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以Google和Apple为例,两家公司都有自己的手机和App, 抽象工厂生产手机和APP,对于不同类型的手机而言,都有共同的一个产品接口,具体的phone类要实现接口,完善具体信息,最终谷歌工厂实现抽象接口,具体以什么方式造手机,由工厂通过产品的实现类来实现,产品的实现类定义了手机的型号,大小等,工厂按照这样去生产。
如果需要增加新产品,需要新产品接口,产品实现类,以及抽象工厂添加产品实现方法,对应工厂实现对应方法。
// 总的抽象工厂接口
public interface AbstractOfficeFactory {
String Phone();
String APP();
}
// app产品接口
public interface AppProduct {
String App();
}
// 手机产品接口
public interface PhoneProduct {
String Phone();
}
public class ApplePhone implements PhoneProduct {
public String Phone() {
return "Apple Phone";
}
}
public class AppleApp implements AppProduct {
public String App() {
return "Apple App";
}
}
/ 苹果工厂生产苹果产品
public class AppleFactory implements AbstractOfficeFactory{
public String Phone() {
return new ApplePhone().Phone();
}
public String APP() {
return new AppleApp().App();
}
}
Google类似......
3.建造者模式
模式定义
建造者模式(Builder Pattern):将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示。
建造者模式是一步一步创建一个复杂的对象,它允许用户只通过指定复杂对象的类型和内容就可以构建它们,用户不需要知道内部的具体构建细节。建造者模式属于对象创建型模式。根据中文翻译的不同,建造者模式又可以称为生成器模式。
建造者模式包含如下角色:
Builder:抽象建造者
ConcreteBuilder:具体建造者
Director:指挥者
Product:产品角色
模式动机
无论是在现实世界中还是在软件系统中,都存在一些复杂的对象,它们拥有多个组成部分,如汽车,它包括车轮、方向盘、发送机等各种部件。而对于大多数用户而言,无须知道这些部件的装配细节,也几乎不会使用单独某个部件,而是使用一辆完整的汽车,可以通过建造者模式对其进行设计与描述,建造者模式可以将部件和其组装过程分开,一步一步创建一个复杂的对象。用户只需要指定复杂对象的类型就可以得到该对象,而无须知道其内部的具体构造细节
在软件开发中,也存在大量类似汽车一样的复杂对象,它们拥有一系列成员属性,这些成员属性中有些是引用类型的成员对象。而且在这些复杂对象中,还可能存在一些限制条件,如某些属性没有赋值则复杂对象不能作为一个完整的产品使用;有些属性的赋值必须按照某个顺序,一个属性没有赋值之前,另一个属性可能无法赋值等。
复杂对象相当于一辆有待建造的汽车,而对象的属性相当于汽车的部件,建造产品的过程就相当于组合部件的过程。由于组合部件的过程很复杂,因此,这些部件的组合过程往往被“外部化”到一个称作建造者的对象里,建造者返还给客户端的是一个已经建造完毕的完整产品对象,而用户无须关心该对象所包含的属性以及它们的组装方式,这就是建造者模式的模式动机。
建造者模式的优点
- 在建造者模式中,客户端不必知道产品内部组成的细节,将产品本身与产品的创建过程解耦,使得相同的创建过程可以创建不同的产品对象。
- 每一个具体建造者都相对独立,而与其他的具体建造者无关,因此可以很方便地替换具体建造者或增加新的具体建造者,用户使用不同的具体建造者即可得到不同的产品对象。
- 可以更加精细地控制产品的创建过程。将复杂产品的创建步骤分解在不同的方法中,使得创建过程更加清晰,也更方便使用程序来控制创建过程。
- 增加新的具体建造者无须修改原有类库的代码,指挥者类针对抽象建造者类编程,系统扩展方便,符合“开闭原则”。
建造者模式的缺点如下: - 建造者模式所创建的产品一般具有较多的共同点,其组成部分相似,如果产品之间的差异性很大,则不适合使用建造者模式,因此其使用范围受到一定的限制。
- 如果产品的内部变化复杂,可能会导致需要定义很多具体建造者类来实现这种变化,导致系统变得很庞大
模式适用环境
在以下情况下可以使用建造者模式:
- 需要生成的产品对象有复杂的内部结构,这些产品对象通常包含多个成员属性。
- 需要生成的产品对象的属性相互依赖,需要指定其生成顺序。
- 对象的创建过程独立于创建该对象的类。在建造者模式中引入了指挥者类,将创建过程封装在指挥者类中,而不在建造者类中。
- 隔离复杂对象的创建和使用,并使得相同的创建过程可以创建不同的产品。
模式应用
(1) JavaMail(一步一步构造一个完整的邮件对象,然后发送)1
2
3
4
5
6
7
8
9
10
11
12
13
14
15//由邮件会话对象新建一个邮件消息对象
MimeMessage message=new MimeMessage(session);
//设置邮件地址
InternetAddress from=new InternetAddress("sunny@test.com");
message.setFrom(from);//设置发件人
InternetAddress to=new InternetAddress(to_mail);
message.setRecipient(Message.RecipientType.TO,to);//设置收件人,并设置其接收类型为TO
message.setSubject(to_title);//设置主题
message.setText(to_content);//设置信件内容
message.setSentDate(new Date());//设置发信时间
message.saveChanges();//存储邮件信息
Transport transport=session.getTransport("smtp");
transport.connect("smtp.test.com","test","test");
transport.sendMessage(message,message.getAllRecipients());
![Alt text](./1605746526666.png)
(2) 在很多游戏软件中,地图包括天空、地面、背景等组成部分,人物角色包括人体、服装、装备等组成部分,可以使用建造者模式对其进行设计,通过不同的具体建造者创建不同类型的地图或人物
建造者模式与抽象工厂模式的比较
- 与抽象工厂模式相比,建造者模式返回一个组装好的完整产品,而抽象工厂模式返回一系列相关的产品,这些产品位于不同的产品等级结构,构成了一个产品族。
- 在抽象工厂模式中,客户端实例化工厂类,然后调用工厂方法获取所需产品对象,而在建造者模式中,客户端可以不直接调用建造者的相关方法,而是通过指挥者类来指导如何生成对象,包括对象的组装过程和建造步骤,它侧重于一步步构造一个复杂对象,返回一个完整的对象。
- 如果将抽象工厂模式看成汽车配件生产工厂,生产一个产品族的产品,那么建造者模式就是一个汽车组装工厂,通过对部件的组装可以返回一辆完整的汽车。
将一个复杂对象的构建与它的表示分离,使得同样的构建过程可以创建不同的表示,这样使得在用户不知道对象的建造过程和细节的情况下就可以直接创建复杂的对象。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//产品的属性,即需要什么配件完成产品
public class Product {
private String aProduct;
private String bProduct;
get/set.......
}
// 要建造某一个东西,经过A,B最终成为一个产品
public abstract class Builder {
abstract void builderA();
abstract void builderB();
abstract Product getProduct();
}
//工人制作产品
public class Worker extends Builder {
private Product product;
public Worker(){
product = new Product();
}
void builderA() {
product.setaProduct("建造a");
}
void builderB() {
product.setbProduct("建造b");
}
Product getProduct() {
return product;
}
}
//指挥的人指挥工人做事,最终得到产品
public class Director {
public Product build(Builder builder) {
builder.builderA();
builder.builderB();
return builder.getProduct();
}
}
public class Test {
public static void main(String[] args) {
Director director = new Director();
Product product = director.build(new Worker());
System.out.println(product);
}
}
可以去除指挥者,直接由工人实现。
4.原型模式
prototype
就是在new的基础上,如果创建对象过于复杂,可以使用clone来实现对象的创建,在对象复杂的情况下,效率是比new高的,一般与工厂模式一起使用。
1.浅克隆:直接实现cloneable接口,重写clone方法,在使用对象时,在基础对象上直接example.clone()就可以实现,缺点是两个对象的引用都指向同一个区域,修改一个,另一个也会修改
2.深克隆:两个对象只得不是同一区域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
63public class Example implements Cloneable{
private String name;
private int age;
private User user;
public Example() {
}
public Example(String name, int age, User user) {
this.name = name;
this.age = age;
this.user = user;
}
//浅拷贝
// @Override
// protected Object clone() throws CloneNotSupportedException {
// return super.clone();
// }
//深拷贝
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Example example = (Example) obj;
example.user= (User) this.user.clone();//重新clone user
return obj;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public User getUser() {
return user;
}
public void setUser(User user) {
this.user = user;
}
public String toString() {
return "Example{" +
"name='" + name + '\'' +
", age=" + age +
", user=" + user +
'}';
}
}
结构型
1.适配器模式
所谓的适配器模式就是将两个本来无关的对象,由于需要将两个对象关联起来,所以需要中间的这个桥梁,即适配器
下面的例子就是通过适配器使得没有网线插口的电脑可以连接网线上网
网线通过usb连接适配器,电脑通过适配器连接网线,实现上网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// 接口,不同适配器可能需要同一个接口去实现不同的功能,所以需要定义接口
public interface USB {
public void linkToNet();
}
public class Adapter implements USB {
private NetLine netLine;
Adapter(NetLine netLine) {
this.netLine = netLine;
}
@Override
public void linkToNet() {
netLine.LinkToNet();
}
}
// 被适配的类:网线
public class NetLine {
public void LinkToNet() {
System.out.println("联网");
}
}
// 电脑类:需要适配器
public class Computer {
public void goToNet(USB adapter) {
adapter.linkToNet();
}
}
2.桥接模式
桥接模式将抽象与实现分离,使得各自可以有独立的变化,比多继承更加简介,扩展性更强,满足开闭原则。
以电脑和品牌为例,电脑组合品牌,即组合模式桥接在一起,想要什么品牌,直接根据类型和平拍new即可。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
65
66
67
68//桥接模式,抽象与现实分离
public interface Brand {
void info();
}
public class Apple implements Brand{
public void info() {
System.out.println("苹果品牌");
}
}
public class HuaWei implements Brand {
public void info() {
System.out.println("华为品牌");
}
}
//抽象的电脑,组合品牌
public abstract class Computer {
protected Brand brand;
public Computer(Brand brand) {
this.brand = brand;
}
public void get() {
brand.info();
}
}
//台式机
public class Desktop extends Computer {
public Desktop(Brand brand) {
super(brand);
}
public void get() {
super.get();
System.out.println("台式机");
}
}
// 移动
public class Move extends Computer {
public Move(Brand brand) {
super(brand);
}
public void get() {
super.get();
System.out.println("移动电脑");
}
}
public class Test {
public static void main(String[] args) {
// 通过桥接模式,连接两个本来没有关联的事物,然后创建一个共同的事物
// 其中Brand品牌和computer是接口和抽象父类,通过组合,再结合具体的实现类,使得可以生产不同牌子的电脑
Computer computer = new Desktop(new HuaWei());
computer.get();
}
}
3.静态代理
被代理类只需要专注做自己的事情,其他事情交给代理来实现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//接口
public interface Marry {
void getMarry();
}
//被代理类
public class Me implements Marry {
public void getMarry() {
System.out.println("I am Marry");
}
}
//代理类
public class MarryProxy implements Marry {
private Me me;
public MarryProxy(Me me) {
this.me = me;
}
public void getMarry() {
method();
me.getMarry();
}
private void method() {
System.out.println("我代理了你");
}
}
4.动态代理
基于反射,实现了对象的动态代理,和静态代理不同其不用重复编写代理类,在代理的过程中可以通过反射获取对象的属性及方法。
关键在于:InvocationHandler
Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
这里是JDK代理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
36public class MyProxy implements InvocationHandler {
private Object target;
public void setTarget(Object target) {
this.target = target;
}
public Object getProxy() {
return Proxy.newProxyInstance(this.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
}
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
Object result = method.invoke(target,args);
return result;
}
public interface Brand {
void info();
}
public class Apple implements Brand {
public void info() {
System.out.println("Apple");
}
}
public class Test {
public static void main(String[] args) {
Apple apple=new Apple();
MyProxy myProxy = new MyProxy();
myProxy.setTarget(apple);
Brand proxy = (Brand) myProxy.getProxy();
proxy.info();
}
}