计算机基础---设计模式

** 简述 设计模式 七大原则 **

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
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值