1.什么是模板方法模式?
答:模板方法模式是指定义一个模板结构,将具体内容延迟到子类去实现。
优点:
提高代码复用性:将相同部分的代码放在抽象的父类中,而将不同的代码放入不同的子类中;
实现了反向控制:通过一个父类调用其子类的操作,通过对子类的具体实现扩展不同的行为,实现了反向控制并且符合开闭原则。
以给冰箱中放水果为例,比如,我要放一个香蕉:开冰箱门 → 放香蕉 → 关冰箱门;如果我再要放一个苹果:开冰箱门 → 放苹果 → 关冰箱门。可以看出它们之间的行为模式都是一样的,只是存放的水果品类不同而已,这个时候就非常适用模板方法模式来解决这个问题,实现代码如下:
/\* \* 添加模板方法 \*/
abstract class Refrigerator {
public void open() {
System.out.println("开冰箱门");
}
public abstract void put();
public void close() {
System.out.println("关冰箱门");
}
}
class Banana extends Refrigerator {
@Override
public void put() {
System.out.println("放香蕉");
}
}
class Apple extends Refrigerator {
@Override
public void put() {
System.out.println("放苹果");
}
}
/\* \* 调用模板方法 \*/
public class TemplateTest {
public static void main(String[] args) {
Refrigerator refrigerator = new Banana();
refrigerator.open();
refrigerator.put();
refrigerator.close();
}
}
2.什么是代理模式?
代理模式是给某一个对象提供一个代理,并由代理对象控制对原对象的引用。
优点:
代理模式能够协调调用者和被调用者,在一定程度上降低了系统的耦合度;
可以灵活地隐藏被代理对象的部分功能和服务,也增加额外的功能和服务。
缺点:
由于使用了代理模式,因此程序的性能没有直接调用性能高;
使用代理模式提高了代码的复杂度。
举一个生活中的例子:比如买飞机票,由于离飞机场太远,直接去飞机场买票不太现实,这个时候我们就可以上携程 App 上购买飞机票,这个时候携程 App 就相当于是飞机票的代理商。
代理模式实现代码如下:
/\* \* 定义售票接口 \*/
interface IAirTicket {
void buy();
}
/\* \* 定义飞机场售票 \*/
class AirTicket implements IAirTicket {
@Override
public void buy() {
System.out.println("买票");
}
}
/\* \* 代理售票平台 \*/
class ProxyAirTicket implements IAirTicket {
private AirTicket airTicket;
public ProxyAirTicket() {
airTicket = new AirTicket();
}
@Override
public void buy() {
airTicket.buy();
}
}
/\* \* 代理模式调用 \*/
public class ProxyTest {
public static void main(String[] args) {
IAirTicket airTicket = new ProxyAirTicket();
airTicket.buy();
}
}
3.什么是单例模式?
答:单例模式是一种常用的软件设计模式,在应用这个模式时,单例对象的类必须保证只有一个实例存在,整个系统只能使用一个对象实例。
优点: 不会频繁地创建和销毁对象,浪费系统资源。
使用场景:IO 、数据库连接、Redis 连接等。
单例模式代码实现:
class Singleton {
private static Singleton instance = new Singleton();
public static Singleton getInstance() {
return instance;
}
}
单例模式调用代码:
public class Lesson7\_3 {
public static void main(String[] args) {
Singleton singleton1 = Singleton.getInstance();
Singleton singleton2 = Singleton.getInstance();
System.out.println(singleton1 == singleton2);
}
}
程序的输出结果:true
可以看出以上单例模式是在类加载的时候就创建了,这样会影响程序的启动速度,那如何实现单例模式的延迟加载?在使用时再创建?
单例延迟加载代码:
// 单例模式-延迟加载版
class SingletonLazy {
private static SingletonLazy instance;
public static SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
以上为非线程安全的,单例模式如何支持多线程?
使用 synchronized 来保证,单例模式的线程安全代码:
class SingletonLazy {
private static SingletonLazy instance;
public static synchronized SingletonLazy getInstance() {
if (instance == null) {
instance = new SingletonLazy();
}
return instance;
}
}
4.什么是简单工厂模式?
答:简单工厂模式又叫静态工厂方法模式,就是建立一个工厂类,对实现了同一接口的一些类进行实例的创建。比如,一台咖啡机就可以理解为一个工厂模式,你只需要按下想喝的咖啡品类的按钮(摩卡或拿铁),它就会给你生产一杯相应的咖啡,你不需要管它内部的具体实现,只要告诉它你的需求即可。
优点:
工厂类含有必要的判断逻辑,可以决定在什么时候创建哪一个产品类的实例,客户端可以免除直接创建产品对象的责任,而仅仅“消费”产品;简单工厂模式通过这种做法实现了对责任的分割,它提供了专门的工厂类用于创建对象;
客户端无须知道所创建的具体产品类的类名,只需要知道具体产品类所对应的参数即可,对于一些复杂的类名,通过简单工厂模式可以减少使用者的记忆量;
通过引入配置文件,可以在不修改任何客户端代码的情况下更换和增加新的具体产品类,在一定程度上提高了系统的灵活性。
缺点:
不易拓展,一旦添加新的产品类型,就不得不修改工厂的创建逻辑;
产品类型较多时,工厂的创建逻辑可能过于复杂,一旦出错可能造成所有产品的创建失败,不利于系统的维护。
简单工厂示意图如下:
简单工厂代码实现:
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;
}
}
5.什么是抽象工厂模式?
答:抽象工厂模式是在简单工厂的基础上将未来可能需要修改的代码抽象出来,通过继承的方式让子类去做决定。
比如,以上面的咖啡工厂为例,某天我的口味突然变了,不想喝咖啡了想喝啤酒,这个时候如果直接修改简单工厂里面的代码,这种做法不但不够优雅,也不符合软件设计的“开闭原则”,因为每次新增品类都要修改原来的代码。这个时候就可以使用抽象工厂类了,抽象工厂里只声明方法,具体的实现交给子类(子工厂)去实现,这个时候再有新增品类的需求,只需要新创建代码即可。
抽象工厂实现代码如下:
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{
@Override
public 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{
@Override
public String createProduct(String product) {
String result = null;
switch (product) {
case "Mocca":
result = "摩卡";
break;
case "Latte":
result = "拿铁";
break;
default:
result = "其他咖啡";
break;
}
return result;
}
}