** 简述 设计模式 七大原则 **
1.开发封闭原则 : 对扩展开放 , 对修改封闭。
在程序需要就行扩展的时候 , 不能去修改 原有的代码, 形成一个 热插拔 的效果。
2.单一职责原则: 一个类 接口 或 方法 只负责 一个 职责 ,降低代码复杂度 以及
变更引起的风险。
3.依赖倒置原则: 针对接口编程 , 依赖于 抽象类 或 接口 而不依赖于 具体实现类。
4.接口隔离原则: 将不同 功能 定义在不同接口中 实现 接口隔离。
5.里氏替换原则: 任何 基类 可以出现的 地方 ,子类 都一定可以 出现。
6.迪米特原则: 每个模块 都要 对 其他模块 尽可能 少地 了解 或 依赖 ,降低 代码耦合度。
7.合成复用原则: 尽量 使用 组合/聚合 而不是 继承 达到 软件复用 的 目的。
** 简述 设计模式 的 分类 **
1.创建型模式: 在创建对象的 同时 隐藏 逻辑 ,不使用 new 直接 实例化对象 。
有(工厂方法模式 抽象工厂模式 单例模式 建造者模式 原型模式)
2.结构型模式: 通过 类和接口 间的 继承和引用 实现 创建 复杂结构的对象。
有 (适配器模式 装饰器模式 代理模式 外观模式 桥接模式 组合模式 享元模式)
3.行为型模式: 通过 类之间 不同 的 通信方法 实现 不同行为。
有 (策略模式、模板方法模式、观察者模式、迭代子模式、责任链模式、命令模式、备忘录模式、状态模式、访问者模式、中介者模式、解释器模式)
** 简述 单例 模式 **
一个单例类 在 任何 情况 下 都 只存在 一个实例。
具体实现
需要:
(1)将构造方法私有化,使其不能在类的外部通过new关键字实例化该类对象。
(2)在该类内部产生一个唯一的实例化对象,并且将其封装为private static类型。
(3)定义一个静态方法返回这个唯一对象。
** 实现一:立即加载 / “饿汉模式” **
立即加载就是使用类的时候已经将对象创建完毕(不管以后会不会使用到该实例化对象,先创建了再说。很着急的样子,故又被称为“饿汉模式”),常见的实现办法就是直接new实例化。
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static、final修饰
private static final Singleton instance = new Singleton();
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
return instance;
}
}
饿汉模式”的优缺点:
优点:实现起来简单,没有多线程同步问题。
缺点:当类SingletonTest被加载的时候,会初始化static的instance,静态变量被创建并分配内存空间,从这以后,这个static的instance对象便一直占着这段内存(即便你还没有用到这个实例),当类被卸载时,静态变量被摧毁,并释放所占有的内存,因此在某些特定条件下会耗费内存。
** 实现二:延迟加载 / “懒汉模式” **
延迟加载就是调用get()方法时实例才被创建(先不急着实例化出对象,等要用的时候才给你创建出来。不着急,故又称为“懒汉模式”),常见的实现方法就是在get方法中进行new实例化。
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static修饰
private static Singleton instance;
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例
public static Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
“懒汉模式”的优缺点:
优点:实现起来比较简单,当类SingletonTest被加载的时候,静态变量static的instance未被创建并分配内存空间,当getInstance方法第一次被调用时,初始化instance变量,并分配内存,因此在某些特定条件下会节约了内存。
缺点:在多线程环境中,这种实现方法是完全错误的,根本不能保证单例的状态。
** 实现三:线程安全的“懒汉模式” **
public class Singleton {
// 将自身实例化对象设置为一个属性,并用static修饰
private static Singleton instance;
// 构造方法私有化
private Singleton() {}
// 静态方法返回该实例,加synchronized关键字实现同步
public static synchronized Singleton getInstance() {
if(instance == null) {
instance = new Singleton();
}
return instance;
}
}
优点:在多线程情形下,保证了“懒汉模式”的线程安全。
缺点:众所周知在多线程情形下,synchronized方法通常效率低,显然这不是最佳的实现方案。
** 实现四:DCL双检查锁机制 **
双重校验锁实现对象单例
package test;
/**
* 双重校验锁实现对象单例(线程安全)
*/
public class Singleton {
private volatile static Singleton uniqueInstance;
public Singleton() {
}
public synchronized static Singleton getUniqueInstance(){
//先判断对象是否已经实例过,没有实例化过才能进入加锁代码
if (uniqueInstance ==null){
//给类对象加锁
synchronized (Singleton.class){
if (uniqueInstance ==null){
uniqueInstance=new Singleton();
}
}
}
return uniqueInstance;
}
}
方法四算是单例模式的最佳实现方式。内存占用率高,效率高,线程安全,多线程操作原子性。
责任链模式
建造者模式
观察者模式
发布订阅模式
** 工厂模式 **
** 简述 简单工厂模式 **
指 由一个工厂对象来创建实例, 适用于 工厂类 负责 创建 对象较少的 情况。
(允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。)
(Spring 中 的 BeanFactory 是由 简单工厂模式 产生Bean对象)
图是简单工厂的UML图。客户端类使用的是Factory类,该类具有create_type()方法。当客户端使用类型参数调用create_type()方法时,Factory会根据传入的参数,返回Product1或Product2。
实现:在下面的代码段中,我们将创建一个名为Animal的抽象产品。Animal是一个抽象的基类(ABCMeta是 Python的特殊元类,用来生成类Abstract),它带有方法do_say()。我们利用Animal接口创建了两种产品(Cat和Dog),并实现了do_say()方法来提供这些动物的相应的叫声。ForestFactory是一个带有make_sound()方法的工厂。根据客户端传递的参数类型,它就可以在运行时创建适当的Animal实例,并输出正确的声音:
from abc import ABCMeta, abstractmethod
#抽象类
class Animal(metaclass = ABCMeta):
@abstractmethod
def do_say(self):
pass
class Dog(Animal):
def do_say(self):
print('汪汪。。。')
class Cat(Animal):
def do_say(self):
print('喵喵。。。')
#工厂类:
class ForestFactory:
def make_sound(self, object_type):
return eval(object_type)().do_say()
#client code
if __name__ == '__main__':
ff = ForestFactory()
animal = input('Which animal should make sound(Dog or Cat)?')
ff.make_sound(animal)
** 简述 工厂方法模式 **
工厂方法模式 指的是 定义 一个 创建对象 的接口 ,让接口的 实现类 决定 创建 哪种对象 , 让 类 的 实例化 推迟到 类中 进行。
(允许接口创建对象,但使用哪个类来创建对象,则是交由子类决定的。)
(Spring 的 FactoryBean 的接口 getObject 方法 也是 工厂方法)
(以下几点可以帮助我们了解工厂方法模式:
(1)我们定义了一个接口来创建对象,但是工厂本身并不负责创建对象,而是将这以任务交由子类来完成,即子类决定了要实例化哪些类;
(2)Factory方法的创建是通过继承而不是通过实例化来完成的;
(3)工厂方法使设计更加具有可定制性。它可以返回相同的实例或子类,而不是某种类型的对象) )
在UML图中,有一个包含factoryMethod()方法的抽象类Creator。factoryMethod()方法负责创建指定类型的对象。ConcreteCreator类提供了一个实现Creator抽象类的factoryMethod()方法,这种方法可以在运行是时修改已创建的对象。ConcreteCreator创建ConcreteProduct,并确保其创建的对象实现了Product类,同时为Product接口中的所有方法提供相应的实现。
简而言之,Creator接口的factoryMethod()方法和ConcreteCreator类共同决定了要创建Product的哪个子类。因此,工厂方法模式定义了一个接口来创建对象,但具体实例化哪个类则是由它的子类决定的。
from abc import ABCMeta, abstractmethod
#抽象Product
class Section(metaclass = ABCMeta):
@abstractmethod
def describe(self): #抽象方法
pass
#ConcreteProduct1
class PersonalSection(Section):
def describe(self):
print('Personal Section!')
#ConcreteProduct2
class AlbumSection(Section):
def describe(self):
print('Album Section!')
#ConcreteProduct3
class PatentSection(Section):
def describe(self):
print('Patent Section!')
#ConcreteProduct4
class PublicationSection(Section):
def describe(self):
print('Publication Section!')
#抽象类Creator
class Profile(metaclass = ABCMeta):
def __init__(self):
self.sections = []
self.createProfile()
@abstractmethod
def createProfile(self):
pass
def getSections(self):
return self.sections
def addSectons(self, section):
self.sections.append(section)
#ConcreteCreator类
class linkedin(Profile):
def createProfile(self):
self.addSectons(PersonalSection())
self.addSectons(PatentSection())
self.addSectons(PublicationSection())
#ConcreteCreator类
class facebook(Profile):
def createProfile(self):
self.addSectons(PersonalSection())
self.addSectons(AlbumSection())
if __name__ == '__main__':
profile_type = input('Which Profile you\'d like to create?(LinkedIn or FaceBook)')
profile = eval(profile_type.lower())() #实例化类
print('Creating Profile...:', type(profile).__name__)
print('Profile has sections...:', profile.getSections())
工厂方法模式的优点:
(1)它具有更大的灵活性,使得代码更加通用,因为它不是单纯地实例化某个类。这样,实现哪些类取决于接口(Product),而不是ConcreteCreator。
(2)它们是松耦合的,因为创建对象的代码与使用它的代码是分开的。客户端完全不需要关心要传递哪些参数以及需要实例化哪些类。由于添加新类更加容易,所以降低了维护成本。
** 简述 抽象工厂 模式 **
抽象工厂模式指的是 一个 创建 一系列 相关 或 相互 依赖对象 的接口 , 无需 指定 它们的具体 实现类。
(抽象工厂是一个能够创建一系列相关的对象而无需指定/公开其具体类的接口。该模式能够提供其他工厂的对象,在其内部创建其他对象。)
(例子:java.sql.Connection 接口。)
如图3所示,ConcreteFactory1 和 ConcreteFactory2 是通过AbstractFactory接口创建的。此接口具有创建多种产品的相应方法。
ConcreteFactory1 和 ConcreteFactory2实现了AbstractFactory,并创建实例 ConcreteProduct1、ConcreteProduct2、AnotherConcreteProduct1和AnotherConcreteProduct2。
在这里,ConcreteProduct1和ConcreteProduct2是通过AbstractProduct接口创建的,而AnotherConcreteProduct1和AnotherConcreteProduct2则是通过AnotherAbstractProduct接口创建的。
实际上,抽象工厂模式不仅确保客户端与对象的创建相互隔离,同时还确保客户端能够使用创建的对象。但是,客户端只能通过接口访问对象。如果要使用一个系列中的多个产品,那么抽象工厂模式能够帮助客户端一次使用来自一个产品/系列的多个对象。
###实现抽象工厂模式
例子:一家披萨店,供应印式和美式披萨饼。为此,我们首先创建一个抽象基类—PizzaFactory(AbstractFactory)。PizzaFactory类有两个抽象方法即createVegPizza()和createNonVegPizza(),它们需要通过ConcreteFactory实现。在这个例子中,我们创建了两个具体的工厂,分别名为IndianPizzaFactory和USPizzaFactory。
from abc import ABCMeta, abstractmethod
#AbstractFactory
class PizzaFactory(metaclass = ABCMeta):
@abstractmethod
def createVegPizza(self):
pass
@abstractmethod
def createNonVegPizza(self):
pass
#ConcreteFactory
class IndianPizzaFactory(PizzaFactory):
def createVegPizza(self):
return DeluxVeggiePizza()
def createNonVegPizza(self):
return ChickenPizza()
#ConcreteFactory
class USPizzaFactory(PizzaFactory):
def createVegPizza(self):
return MexicanVegPizza()
def createNonVegPizza(self):
return HamPizza()
#进一步定义 AbstractProducts:
#AbstractProduct
class VegPizza(metaclass = ABCMeta):
@abstractmethod
def prepare(self, VegPizza): #定义自己的方法
pass
#AnotherAbstractProduct
class NonVegPizza(metaclass = ABCMeta):
@abstractmethod
def serve(self, VegPizza): #定义自己的方法
pass
#为每个AbstractProducts定义ConcreteProducts,创建DeluxVeggiePizza和MexicanVegPizza:
class DeluxVeggiePizza(VegPizza): #ConcreteProducts1
def prepare(self):
print('Prepare:', type(self).__name__)
#定义AnotherConcreteProduct:
class MexicanVegPizza(VegPizza): #ConcreteProducts2
def prepare(self):
print('Prepare:', type(self).__name__)
#定义ChickenPizza和HamPizza,分别代表AnotherConcreteProducts1和AnotherConcreteProducts2:
class ChickenPizza(NonVegPizza): #AnotherConcreteProducts1
def serve(self, VegPizza):
print(type(self).__name__, ' is served with Chicken on ', type(VegPizza).__name__)
class HamPizza(NonVegPizza):
def serve(self, VegPizza):
print(type(self).__name__, ' is served with Ham on ', type(VegPizza).__name__)
#当最终用户来到PizzaStore并要一份美式非素食披萨的时候,USPizzaFactory负责准备素食,
#然后在上面加上火腿,马上就变成非素食披萨了:
class PizzaStore:
def __init__(self):
pass
def makePizzas(self):
for factory in [IndianPizzaFactory(), USPizzaFactory()]:
self.factory = factory
self.NonVegPizza = self.factory.createNonVegPizza()
self.VegPizza = self.factory.createVegPizza()
self.VegPizza.prepare()
self.NonVegPizza.serve(self.VegPizza)
if __name__ == '__main__':
pizza = PizzaStore()
pizza.makePizzas()
** 简述 代理模式 **
代理模式为其他对象 提供 一种 代理 以 控制 对 这个对象 的 访问。
为什么要用代理模式?
1.中介隔离作用:在某些情况下,一个客户类不想或者不能直接引用一个委托对象,而代理类对象可以在客户类和委托对象之间起到中介的作用,其特征是代理类和委托类实现相同的接口。
2.开闭原则,增加功能:代理类除了是客户类和委托类的中介之外,我们还可以通过给代理类增加额外的功能来扩展委托类的功能,这样做我们只需要修改代理类而不需要再修改委托类,符合代码设计的开闭原则。代理类主要负责为委托类预处理消息、过滤消息、把消息转发给委托类,以及事后对返回结果的处理等。代理类本身并不真正实现服务,而是同过调用委托类的相关方法,来提供特定的服务。真正的业务功能还是由委托类来实现,但是可以在业务功能执行的前后加入一些公共的服务。例如我们想给项目加入缓存、日志这些功能,我们就可以使用代理类来完成,而没必要打开已经封装好的委托类。
静态代理: 在程序 运行前 就已经 存在 代理类 的 字节码文件, 代理类和委托类 的 关系 在运行前 就确定了。
第一步:创建服务类接口
package main.java.proxy;
public interface BuyHouse {
void buyHosue();
}
第二步:实现服务接口
import main.java.proxy.BuyHouse;
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("我要买房");
}
}
第三步:创建代理类
package main.java.proxy.impl;
import main.java.proxy.BuyHouse;
public class BuyHouseProxy implements BuyHouse {
private BuyHouse buyHouse;
public BuyHouseProxy(final BuyHouse buyHouse) {
this.buyHouse = buyHouse;
}
@Override
public void buyHosue() {
System.out.println("买房前准备");
buyHouse.buyHosue();
System.out.println("买房后装修");
}
}
第四步:编写测试类
import main.java.proxy.impl.BuyHouseImpl;
import main.java.proxy.impl.BuyHouseProxy;
public class ProxyTest {
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
buyHouse.buyHosue();
BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
buyHouseProxy.buyHosue();
}
}
静态代理总结:
优点:可以做到在符合开闭原则的情况下对目标对象进行功能扩展。
缺点:我们得为每一个服务都得创建代理类,工作量太大,不易管理。同时接口一旦发生改变,代理类也得相应修改。
动态代理: 程序运行期间动态的生成 , 所以 不存在代理类 的 字节码文件。
代理类和 委托类 的 关系 是在 程序 运行时确定。
第一步:编写动态处理器
package main.java.proxy.impl;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
public class DynamicProxyHandler implements InvocationHandler {
private Object object;
public DynamicProxyHandler(final Object object) {
this.object = object;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("买房前准备");
Object result = method.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
第二步:编写测试类
package main.java.proxy.test;
import main.java.proxy.BuyHouse;
import main.java.proxy.impl.BuyHouseImpl;
import main.java.proxy.impl.DynamicProxyHandler;
import java.lang.reflect.Proxy;
public class DynamicProxyTest {
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
BuyHouse proxyBuyHouse = (BuyHouse) Proxy.newProxyInstance(BuyHouse.class.getClassLoader(), new
Class[]{BuyHouse.class}, new DynamicProxyHandler(buyHouse));
proxyBuyHouse.buyHosue();
}
}
注意Proxy.newProxyInstance()方法接受三个参数:
ClassLoader loader:指定当前目标对象使用的类加载器,获取加载器的方法是固定的
Class<?>[] interfaces:指定目标对象实现的接口的类型,使用泛型方式确认类型
InvocationHandler:指定动态处理器,执行目标对象的方法时,会触发事件处理器的方法
动态代理总结:虽然相对于静态代理,动态代理大大减少了我们的开发任务,同时减少了对业 务接口的依赖,降低了耦合度。但是还是有一点点小小的遗憾之处,那就是它始终无法摆脱仅支持interface代理的桎梏,因为它的设计注定了这个遗憾。回想一下那些动态生成的代理类的继承关系图,它们已经注定有一个共同的父类叫Proxy。Java的继承机制注定了这些动态代理类们无法实现对class的动态代理,原因是多继承在Java中本质上就行不通。有很多条理由,人们可以否定对 class代理的必要性,但是同样有一些理由,相信支持class动态代理会更美好。接口和类的划分,本就不是很明显,只是到了Java中才变得如此的细化。如果只从方法的声明及是否被定义来考量,有一种两者的混合体,它的名字叫抽象类。实现对抽象类的动态代理,相信也有其内在的价值。此外,还有一些历史遗留的类,它们将因为没有实现任何接口而从此与动态代理永世无缘。如此种种,不得不说是一个小小的遗憾。但是,不完美并不等于不伟大,伟大是一种本质,Java动态代理就是佐例。
3.CGLIB代理
JDK实现动态代理需要实现类通过接口定义业务方法,对于没有接口的类,如何实现动态代理呢,这就需要CGLib了。CGLib采用了非常底层的字节码技术,其原理是通过字节码技术为一个类创建子类,并在子类中采用方法拦截的技术拦截所有父类方法的调用,顺势织入横切逻辑。但因为采用的是继承,所以不能对final修饰的类进行代理。JDK动态代理与CGLib动态代理均是实现Spring AOP的基础。
第一步:创建CGLIB代理类
package dan.proxy.impl;
import net.sf.cglib.proxy.Enhancer;
import net.sf.cglib.proxy.MethodInterceptor;
import net.sf.cglib.proxy.MethodProxy;
import java.lang.reflect.Method;
public class CglibProxy implements MethodInterceptor {
private Object target;
public Object getInstance(final Object target) {
this.target = target;
Enhancer enhancer = new Enhancer();
enhancer.setSuperclass(this.target.getClass());
enhancer.setCallback(this);
return enhancer.create();
}
public Object intercept(Object object, Method method, Object[] args, MethodProxy methodProxy) throws Throwable {
System.out.println("买房前准备");
Object result = methodProxy.invoke(object, args);
System.out.println("买房后装修");
return result;
}
}
第二步:创建测试类
package dan.proxy.test;
import dan.proxy.BuyHouse;
import dan.proxy.impl.BuyHouseImpl;
import dan.proxy.impl.CglibProxy;
public class CglibProxyTest {
public static void main(String[] args){
BuyHouse buyHouse = new BuyHouseImpl();
CglibProxy cglibProxy = new CglibProxy();
BuyHouseImpl buyHouseCglibProxy = (BuyHouseImpl) cglibProxy.getInstance(buyHouse);
buyHouseCglibProxy.buyHosue();
}
}
CGLIB代理总结: CGLIB创建的动态代理对象比JDK创建的动态代理对象的性能更高,但是CGLIB创建代理对象时所花费的时间却比JDK多得多。所以对于单例的对象,因为无需频繁创建对象,用CGLIB合适,反之使用JDK方式要更为合适一些。同时由于CGLib由于是采用动态创建子类的方法,对于final修饰的方法无法进行代理。
** 简述 适配器 模式**
适配器模式 将 一个 接口 转换成 客户 希望的 另一个接口 ,使 接口 不兼容的 那些类 可以一起工作。
https://www.jianshu.com/p/9d0575311214
** 简述 装饰器模式 **
装饰器模式可以 动态地 给 对象 添加 一些 额外的 属性 或 行为, 即 需要 修改原有的功能,但又 不愿意 直接 去修改 原有的 代码时候, 设计 一个 Decorator 套 在 原有代码外面。
** 简述 观察者模式 **
观察者模式 表示的是 一种对象 与 对象 之间 具有依赖关系, 当一个对象的状态发生改变时,所有依赖于 它的 对象 都得到 通知 并被 自动更新。
https://www.jianshu.com/p/8b3152c77245
责任链 模式
http://c.biancheng.net/view/1383.html
发布订阅 模式
https://blog.csdn.net/tjvictor/article/details/5223309
建造者模式
https://www.jianshu.com/p/be290ccea05a