浅谈设计模式
??? 在我们平时的编程中经常会遇到“牵一发而动全身的”代码改写的情况,一个程序都是在不断地改进中,不过如果我们在编写代码的时候高耦合太多余严重,那么当我们要添加或者修改功能的时候、、、会不会有种崩溃的感觉?
??? 那么这种问题要怎么解决呢,现在我们的编程是面向对象的就其实大大解决了很多高耦合的情况,但是对于个个类之间的传值和之间的关联还是有很多,而设计模式就解决了大多我们纠结的这种问题。
??? 设计模式有23种不同的模式,对于每一种都有适用的情况和其各自的有点,我就我自己看的和理解的谈一下对“工厂模式”和? “ 单例模式”
?????????????????????????????????????????? 工厂模式
??? 工厂模式主要是为创建对象提供过渡接口,以便将创建对象的具体过程屏蔽隔离起来,达到提高灵活性的目的。也就是对于修改的增添的解耦。
??? 工厂模式在java中主要有:
?????????? 1)简单工厂模式(Simple Factory)
?????????? 2)工厂方法模式(Factory Method)
?????????? 3)抽象工厂模式(Abstract Factory)
??? 一)、简单工厂模式又称静态工场模式,因为在简单工厂模式中对于对象的创建是利用静态方法实现对像创建的传递的,简单工场模式的组成很简单,就是对于工场要生产的产品定义一个产品接口,接口中有属于产品的共同的一个使用方法,而不同具体的产品来实现这个接口,而我们的工厂类就是利用静态的方法通过传递一个唯一的标识来生产需要的产品,又通过抽象产品的声明来调用产品的使用方法,这样对于不同的产品我们就可以实现屏蔽生产过程的调用。
?? 例如,老板要司机开着车出去旅游,如果在程序中我们的是实现就是“开着'大奔'去旅游”把我们开的车的具体实例用在了行程中,而我们需要的是”开车去旅游“用简单工场模式的实现就是:
?? //抽象产品角色
?? public interface Car{
??????? public void drive();
?? }
?? //具体产品角色
?? public class Benz implements Car{
?????? public void drive() {
???????????? System.out.println("Driving Benz ");
????? }
? }
?? public class Bmw implements Car{
??????? public void drive() {
?????????? System.out.println("Driving Bmw ");
??????? }
?? }
? //工厂类角色
?? public class Driver{
? //工厂方法.注意返回类型为抽象产品角色
? public static Car driverCar(String s)throws Exception {
???? //判断逻辑,返回具体的产品角色给Client
??????? if(s.equalsIgnoreCase("Benz"))
??????????? return new Benz();
??????? else if(s.equalsIgnoreCase("Bmw"))
??????????? return new Bmw();
????????? ......
??????? else throw new Exception();
??????? 。。。
??? //老板
????? public class Magnate{
????????? public static void main(String[] args){
????????? try{
???????????? //告诉司机我今天坐奔驰
??????????? Car car = Driver.driverCar("benz");
??????????? //下命令:开车
??????????? car.drive();
?????? 这样对于我们开的什么车去旅游就被隔离了。
?????? 二)、 工厂方法模式
?????? 但是这样对于这种我们可以明显看出一个缺点就是当我们要添加一个产品(车)的时候就会在工厂里面加一个判断逻辑的“标识”,这明显不符合“开闭原则”
所以我们又面临的问题就是怎么让这个判断逻辑省略掉,也就是在我们生产产品的隔离的时候可不可以像产品一样一个抽象的接口,通过实现接口来实现不同的产品的创建的隔离——这就是工厂方法模式。
???? 工厂方法模式比简单工厂模式多的就是对于工场分成了抽象工厂和具体工厂;
?
??? //抽象工厂角色
??? public interface Driver{
?????????? public Car driverCar();
??? }
??? public class BenzDriver implements Driver{
?????????? public Car driverCar(){
????????????? return new Benz();
????????? }
???? }
???? public class BmwDriver implements Driver{
?????????? public Car driverCar() {
??????????????? return new Bmw();
????????? }
????? }
???? //应该和具体产品形成对应关系...
???? //老板
? public class Magnate{
?????????? public static void main(String[] args){
??????????????? try{
??????????????????????? Driver driver = new BenzDriver();
??????????????????????? Car car = driver.driverCar();
???????????????????????? car.drive();
????????????????????? }
????????????????? ……
?? }
三)、抽象工厂模式
????? 抽象工厂模式主要的区别在于引入了产品族 的感念,对于不同产品的同一种特征的产品称为一个产品族,例如奔驰和宝马的跑车系列是一个产品族。而工厂模式中没一个具体的工场模式可以生产的产品都是同一个产品族的产品,这种模式下必须要保证每次使用的都是同一种产品族中的产品。就是一个跑车工厂下可以生产奔驰跑车也可以生产宝马跑车。这样主要就是可以减少对于不同产品的工厂创建的减少。
???? 工厂模式的使用场景:
1) 当客户程序不需要知道要使用对象的创建过程。
2) 客户程序使用的对象存在变动的可能,或者根本就不知道使用哪一个具体的对象。
?????????????????????????????????????????????? 单例模式
????? 对于这种模式我们只从名字上就可以做一个大概的理解,就相当于我们所用的静态变量,而不同的是这个变量是一个对象。
???? 对于他的理解我们其实就可以借助对于静态变量的理解,静态变量就是在内存中有固定的空间的存储的数据(个人理解),包中的所有的方法都可以通过这个空间的引用来使用修改这个数据。也就是这个数据是唯一的公用的。在代码中我们的怎么实现呢?
??????????????????????????????? 1)、饿汉式
???? public class Singleton {
?????????? //在自己内部定义自己一个实例
?????????? //注意这是private 只供内部调用
?????????? private static Singleton instance = new Singleton();
????????? //如上面所述,将构造函数设置为私有
????????? private Singleton(){
?????????? }
?????????? //静态工厂方法,提供了一个供外部访问得到对象的静态方法
?????????? public static Singleton getInstance() {
??????????????????? return instance;
????????? }
???? }
???????????????????????????????????? 2)、懒汉式:
?????? public class Singleton {
????????? //和上面有什么不同?
?????? private static Singleton instance = null;
???????? //设置为私有的构造函数
?????? private Singleton(){
????? }
????? //静态工厂方法
????? public static synchronized Singleton getInstance() {
?????????????? //这个方法比上面有所改进
?????????????? if (instance==null)
????????????????? instance=new Singleton();
???????????? return instance;
?????? }
}
????? 这是java的两种实现方式比较这两种方式,共同的都是构造方法私有,断开了构造函数创建对象的通道,都是通过静态实例化了本类。
???? 区别:
????????? 1、对于创建对象第一种在加载的时候就被实例化,而第二种则是在第一 次调用的时候实例 ? ? ? ? ? ? 化
????????? 2、对于第二种犹豫是在方法调用中实例化就可能会出现在多线程同步调用的情况下创建多 ? ? ? ? ? ?个实例,所以需要synchonized同步来防止,而第 ?一种不会出现这种情况。
? ? ? ? ? PS:但是考虑到多个方法同时调用是也会造成的冲突,个人感觉第 一 种 发放也是需要用 ? ? ? ? ? ?到同步的。
??????? 以上两种实现方式均失去了多态性,不允许被继承。还有另外一种灵活点的 ?实 ? 现,将构造函数设置为受保护的,这样允许被继承产生子类。这种方式在????? 具体实??? 现上又有所不同,可以将父类中获得对象的静态方法放到子类中再实????? 现;也可以??? 在父类的静态方法中进行条件判断来决定获得哪一个对象。
? ? ? ? 但是这样由于在 java 中子类的构造函数的范围不能比父类的小,所以可能造成?? 单例模式失效。
?
补充:
??单例模式邪恶论:
? ? ? ? ? ? ? ? ? ??多个虚拟机;
? ? ? ? ? ? ? ? ? ??多个类加载器;
? ? ? ? ? ? ? ? ? ? 串行化;
? 这里重点说一下串行化:
? ? ? ?一个串行化的对象在每次返串行化的时候,都会创建一个新的对象,而不仅仅是
? 一个对原有对象的引用,这样就违背了串行化的特征,为了解决这个问题,在Serializable中实现readResolve的方法
?
? ?public final class MySingleton implements Serializable{
? ? ? ? ? ? public static final MySingleton INSTANCE = new MySingleton();
? ? ? ? ? ? private MySingleton(){
? ? ? ? ? ? }
? ? ? ? ? ?public static MySingleton getInstatnce(){
? ? ? ? ? ? ? ? ?return INSTANCE;
? ? ? ? ? }
? ? ? ? ?private Object readResolve() throws ObjectStreamException{
? ? ? ? ? ? ? ? ? ? ?//instead of the object we're on,
? ? ? ? ? ? ? ? ? ? //return the class valiable INSTANCE
? ? ? ? ? ? ? ? ? ?return INSTANCE;
? ? ? ? ? ?}
}
? ? ? ? ? ? 这样当JVM从内存中反序列化地"组装"一个新对象时,就会自动调用这个 readResolve方法来返回我们指定好的对象了, 单例规则也就得到了保证.
?