Java高频面试集-基础-设计模式
设计模式
目前来说最好理解的博客:
https://www.jianshu.com/p/61b67ca754a3
1、单例模式
1.1、恶汉
//类创建就加载
public class Singleton{
private static Singleton instance = new Singleton();
public static Singleton getInstance(){
return instance ;
}
1.1、懒汉
//需要用的时候才创建
public class Singleton02{
private static Singleton02 instance;
public static Singleton02 getInstance(){
if (instance == null){
synchronized (Singleton02.class){
if (instance == null){
instance = new Singleton02();
}
}
}
return instance;
}
}
2、工厂模式
2.1、简单工厂
定义:简单地说,简单工厂模式通常就是这样,一个工厂类 XxxFactory,里面有一个静态方法,根据我们不同的参数,返回不同的派生自同一个父类(或实现同一接口)的实例对象。
public class FoodFactory {
public static Food makeFood(String name) {
if (name.equals("noodle")) {
Food noodle = new LanZhouNoodle();
noodle.addSpicy("more");
return noodle;
} else if (name.equals("chicken")) {
Food chicken = new HuangMenChicken();
chicken.addCondiment("potato");
return chicken;
} else {
return null;
}
}
}
2.2、工厂方法
定义:核心在于,我们需要在第一步选好我们需要的工厂。
第一步,我们需要选取合适的工厂,然后第二步基本上和简单工厂一样。
public interface FoodFactory {
Food makeFood(String name);
}
public class ChineseFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new ChineseFoodA();
} else if (name.equals("B")) {
return new ChineseFoodB();
} else {
return null;
}
}
}
public class AmericanFoodFactory implements FoodFactory {
@Override
public Food makeFood(String name) {
if (name.equals("A")) {
return new AmericanFoodA();
} else if (name.equals("B")) {
return new AmericanFoodB();
} else {
return null;
}
}
}
// 客户端调用
public class APP {
public static void main(String[] args) {
// 先选择一个具体的工厂
FoodFactory factory = new ChineseFoodFactory();
// 由第一步的工厂产生具体的对象,不同的工厂造出不一样的对象
Food food = factory.makeFood("A");
}
}
2.3、抽象工厂
定义:当涉及到产品族的时候,就需要引入抽象工厂模式了。
一个经典的例子是造一台电脑。我们先不引入抽象工厂模式,看看怎么实现。
因为电脑是由许多的构件组成的,我们将 CPU 和主板进行抽象,然后 CPU 由 CPUFactory 生产,主板由 MainBoardFactory 生产,然后,我们再将 CPU 和主板搭配起来组合在一起,如下图:
QQ20191025-135454.png
这个时候的客户端调用是这样的:
// 得到 Intel 的 CPU
CPUFactory cpuFactory = new IntelCPUFactory();
CPU cpu = intelCPUFactory.makeCPU();
// 得到 AMD 的主板
MainBoardFactory mainBoardFactory = new AmdMainBoardFactory();
MainBoard mainBoard = mainBoardFactory.make();
// 组装 CPU 和主板
Computer computer = new Computer(cpu, mainBoard);
单独看 CPU 工厂和主板工厂,它们分别是前面我们说的工厂模式
。这种方式也容易扩展,因为要给电脑加硬盘的话,只需要加一个 HardDiskFactory 和相应的实现即可,不需要修改现有的工厂。但是,这种方式有一个问题,那就是如果 Intel 家产的 CPU 和 AMD 产的主板不能兼容使用
,那么这代码就容易出错,因为客户端并不知道它们不兼容,也就会错误地出现随意组合。
下面就是我们要说的产品族的概念,它代表了组成某个产品的一系列附件的集合:
QQ20191025-135712.png
当涉及到这种产品族的问题的时候,就需要抽象工厂模式来支持了。我们不再定义 CPU 工厂、主板工厂、硬盘工厂、显示屏工厂等等,我们直接定义电脑工厂,每个电脑工厂负责生产所有的设备,这样能保证肯定不存在兼容问题。
QQ20191025-135739.png这个时候,对于客户端来说,不再需要单独挑选 CPU厂商、主板厂商、硬盘厂商等,直接选择一家品牌工厂,品牌工厂会负责生产所有的东西,而且能保证肯定是兼容可用的。
public static void main(String[] args) {
// 第一步就要选定一个“大厂”
ComputerFactory cf = new AmdFactory();
// 从这个大厂造 CPU
CPU cpu = cf.makeCPU();
// 从这个大厂造主板
MainBoard board = cf.makeMainBoard();
// 从这个大厂造硬盘
HardDisk hardDisk = cf.makeHardDisk();
// 将同一个厂子出来的 CPU、主板、硬盘组装在一起
Computer result = new Computer(cpu, board, hardDisk);
}
当然,抽象工厂的问题也是显而易见的,比如我们要加个显示器,就需要修改所有的工厂,给所有的工厂都加上制造显示器的方法。这有点违反了对修改关闭,对扩展开放这个设计原则。
3、策略模式
4、装饰模式
装饰者模式:若要扩展功能,装饰者提供了比集成更有弹性的替代方案,动态地将责任附加到对象上。
-
1、装备的超类:IEquip.java
-
2、各个装备的实现类:
-
eg:武器的实现类: ArmEquip.java* 3、装饰品的超类(装饰品也属于装备):IEquipDecorator.java
-
4、装饰品的实现类:
-
eg:蓝宝石的实现类(可累加): BlueGemDecorator.java
-
-
5、最后测试:计算攻击力和查看描述:
Log.e("---", "一个镶嵌2颗红宝石,1颗蓝宝石的靴子: ");
IEquip iEquip = new RedGemDecotator(new RedGemDecotator(new BlueGemDecotator(new ShoeEquip())));
Log.e("---", "攻击力:" + iEquip.caculateAttack());
Log.e("---", "描述语:" + iEquip.description());
5、代理模式
定义:为其他对象提供一种代理以控制对这个对象的访问。在某些情况下,一个客户不想或者不能直接引用另一个对象,而代理对象可以在客户端和目标对象之间起到中介的作用。
比如:微商。一般都是厂家委托给代理商进行销售,顾客跟代理商打交道,而不直接与产品实际生产者进行关联。
6、建造者模式
7、观察者模式
实际生活的例子:下面就以微信服务号为背景,给大家介绍观察者模式。
Java开发中的例子:RabbitMQ
如上图所示,服务号就是我们的主题,使用者就是观察者。现在我们明确下功能:
- 服务号就是主题,业务就是推送消息
- 观察者只需要订阅主题,只要有新的消息就会送来
- 当不想要此主题消息时,取消订阅
- 只要服务号还在,就可以一直有人订阅
8、适配器模式
定义:将一个类的接口转换成客户期望的另一个接口,适配器让原本接口不兼容的类可以相互合作。这个定义还好,说适配器的功能就是把一个接口转成另一个接口。
- 以充电器为实例: 手机充电器一般都是5V左右吧,咱天朝的家用交流电压220V,所以手机充电需要一个适配器(降压器)
9、外观模式
定义:提供一个统一的接口,用来访问子系统中的一群接口,外观定义了一个高层的接口,让子系统更容易使用。其实就是为了方便客户的使用,把一群操作,封装成一个方法。
工作中的例子:
APP的首页需要读取很多接口,如:广告,商品,活动,分类等等。使用外观模式可以将所有的接口整合成一个接口,统一输出。
参考
https://blog.csdn.net/lmj623565791/article/details/25837275