设计模式详解

前言:使用设计模式的目的是为了代码重用,避免程序大量修改,同时使代码更容易理解。在没学会设计模式以前,我喜欢申明不少的类,实现不少的借口,不少类之间看似很类似,但总不知道该如何使代码看起来更加简洁,本身写的代码几乎只有本身看得懂,没有可读性,直到学了设计模式,顿时茅塞顿开,下面就个人一些理解和你们一块儿分享。本文主要讲的是三种常见的设计模式——单例模式、工厂模式和适配器模式。java

一、单例模式设计模式

单例模式的做用在于保证在整个应用程序的生命周期中,任何一个时刻,单例类的实例最多只有一个。那何时须要用到单例模式呢?举个简单的例子,好比实验室里的打印机,实验室10我的都有可能去使用打印机,每一个人的计算机都能链接打印机,为了不两我的的材料同时输出到打印机上,此时打印机就可使用单例模式,即一台打印机只有一个打印程序的实例。通常来讲,单例模式都是自行实例化,并向整个系统提供这个实例单例模式。为了保证系统中只有一个实例,这就须要把单例类的构造函数声明为私有,同时提供一个全局访问点。例如:安全

public class Test{
   //构造函数必须私有
   private Test();
   private static Test uniqueInstance=new Test();
 
   //此为全局访问点
   public static Test getInstance(){
       return uniqueInstance;   
   }

}

上例也说明了为何单例模式是自行实例化,由于在使用前对象就已经建立好了(uniqueInstance),要使用只需调用public的getInstance方法便可。所以,单例模式在多线程环境下是试用的。最典型的例子就是Hibernate下的SessionFactory了,由于SessionFactory须要线程安全,能被多个线程同时访问,全部为了方便使用,用单例模式来实现,具体的能够自行去看Hibernate有关的知识点。多线程

二、工厂模式ide

通常来讲,工厂模式专门负责实例化有大量公共接口的类,它能够动态的决定将哪个类实例化,而不须要事先知道每次要实例化哪个类。函数

1)简单工厂模式。简单工厂模式的工厂类是根据提供给他的参数,返回的是可能产品中的一个类的实例。所以,简单工厂模式又称静态工厂方法模式。它存在的目的很简单:定义一个用于建立对象的接口。它的构成包括:测试

    (1) 工厂类角色:这是本模式的核心,含有必定的商业逻辑和判断逻辑。在java中它每每由一个具体类实现。

       (2) 抽象产品角色:它通常是具体产品继承的父类或者实现的接口。在java中由接口或者抽象类来实现。

       (3)具体产品角色:工厂类所建立的对象就是此角色的实例。在java中由一个具体类实现。spa

好比:线程

(百度上找的图,本身都呵呵了,仔细看不难发现带三角形箭头的箭头表示继承或实现关系,不带三角形的箭头表示建立关系,及工厂与产品的关系)设计

从上图咱们看到,SimpleFactory既是工厂类角色,它与Machine的关系在于其内部有返回Machine类(即为抽象产品角色)的方法,此方法根据不一样的参数返回不一样的Machine实现类,此图中返回的就是具体产品角色(Washer、Televisor、Refrigerator)。

public interface Machine {
    //此处代码省略
}

public class Refrigerator implements Machine {
    //此处代码省略
}

public class Televisor implements Machine {
    //此处代码省略
}

public class Washer implements Machine {
    //此处代码省略
}

public class SimpleFactory {
    public Machine create(int n) {
        if(n==1)return new Refrigerator();
       else if(n==2)return new Televisor();
       else return new Washer();
    }
}

2)工厂方法模式

工厂方法模式是简单工厂模式的进一步抽象化和推广,工厂方法模式里再也不只由一个工厂类决定那一个产品类应当被实例化,这个决定被交给抽象工厂的子类去作。它是类的建立模式,其用意是定义一个用于建立产品对象的工厂的接口,而将实际建立工做推迟到工厂接口的子类中。多态的使用,使得工厂方法模式保持了简单工厂模式的优势,而克服了其缺点。其组成以下:

  (1)抽象工厂角色: 这是工厂方法模式的核心,它与应用程序无关。是具体工厂角色必须实现的接口或者必须继承的父类。在java中它由抽象类或者接口来实现。

      (2)具体工厂角色:它含有和具体业务逻辑有关的代码。由应用程序调用以建立对应的具体产品的对象。

      (3)抽象产品角色:它是具体产品继承的父类或者是实现的接口。在java中通常有抽象类或者接口来实现。

      (4)具体产品角色:具体工厂角色所建立的对象就是此角色的实例。在java中由具体的类来实现。

先看个图:

(又是百度的图片,哈哈,来者不拒,谁让我懒得画)


上图的带有三角形的箭头的箭头表示实现的关系(concreteCreatorA和B都是实现的接口Creator),虚线箭头表示工厂与产品的关系,即实现产品对象的实例化。从上图咱们能够看出来,接口或抽象类Creator即为抽象工厂角色,concreteCreatorA和B是具体工厂角色,Product是抽象产品角色,concreteProductA和B是具体产品角色。Creator实现了对产品的全部操做方法,而不实现产品对象的实例化,全部产品的实例化(concreteProductA和B)由Creator的子类(concreteCreatorA和B)来完成。听起来有点抽象,下面来看看代码。

//抽象产品角色,至关于上述的Product
public interface Moveable {
    void run();
}
//具体产品角色,至关于concreteProductA和B
public class Plane implements Moveable {
    @Override
    public void run() {
        System.out.println("plane....");
    }
}

public class Broom implements Moveable {
    @Override
    public void run() {
        System.out.println("broom.....");
    }
}

//抽象工厂角色,至关于Creator
public abstract class VehicleFactory {
    abstract Moveable create();
}
//具体工厂角色,至关于concreteCreatorA和B
public class PlaneFactory extends VehicleFactory{
    public Moveable create() {
        return new Plane();
    }
}
public class BroomFactory extends VehicleFactory{
    public Moveable create() {
        return new Broom();
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        VehicleFactory factory = new BroomFactory();
        Moveable m = factory.create();
        m.run();
    }
}

从代码应该能比较明显的看出上述四个角色的逻辑关系,这样也就能理解工厂方法模式了。

简单工厂和工厂方法模式的比较:

工厂方法模式和简单工厂模式在定义上的不一样是很明显的。工厂方法模式的核心是一个抽象工厂类,而不像简单工厂模式, 把核心放在一个实类上。工厂方法模式能够容许不少实的工厂类从抽象工厂类继承下来, 从而能够在实际上成为多个简单工厂模式的综合,从而推广了简单工厂模式。 
反过来说,简单工厂模式是由工厂方法模式退化而来。设想若是咱们很是肯定一个系统只须要一个实的工厂类, 那么就不妨把抽象工厂类合并到实的工厂类中去。而这样一来,咱们就退化到简单工厂模式了。

 

3)抽象工厂模式

抽象工厂模式是全部形态的工厂模式中最为抽象和最具通常性的一种形态。它指的是当有多个抽象角色时,抽象工厂模式能够向客户端提供一个接口,使客户端在没必要指定产品的具体的状况下,建立多个产品族中的产品对象。在抽象工厂模式中,抽象产品 (AbstractProduct) 多是一个或多个,从而构成一个或多个产品族(Product Family)。 在只有一个产品族的状况下,抽象工厂模式实际上退化到工厂方法模式。

按惯例,先看抽象工厂模式的设计类图。(实线段表示继承或实现的关系,虚线表示工厂与产品的关系)

AbstractProductA和AbstractProductB各表明一个产品家族,实现这些接口的类表明具体的产品,AbstractFactory为建立产品的接口,可以建立全部产品家族中的全部类型的产品,它的子类(ConcreteFactory1和2)能够根据具体状况建立对应的产品。换句话说,Client须要的只是类型与这些抽象产品角色相同的一些实例,而不是这些抽象产品的实例。能够把上图想象成苹果公司,接口AbstractFactory即为苹果总公司(总公司是抽象的,总公司大楼并不生产产品),而ConcreteFactory1和2能够表示其在亚洲和美洲的生产基地(是具体的,是苹果总公司在亚洲和美洲的具体实现)。而AbstractProductA表示Iphone系列,是抽象的产品家族,假设此系列目前流水线上有两款手机产品一是iPhone6s(ProductA1,主要在亚洲基地ConcreteFactory1生产),另外一个是iPhone7(ProductA2,还未在亚洲上市,只能在美洲ConcreteFactory2生产)。AbstractProductA表示Ipad系列,B1在亚洲(ConcreteFactory1)生产,B2在美洲ConcreteFactory2生产。而每一个人(Client)要买苹果系列都须要向苹果总公司提交网上申请。此时我想买个iPhone7,那我根本不会关系iPhone7是在哪里生产的,我只须要一个iPhone7而已(即类型与ProductA2相同的一个实例),苹果总公司内部是怎么运做的我不须要知道,但我知道苹果总公司能给我任何它旗下产品族的一个产品。这就是抽象工厂的概念,解释的可能不够严谨,下面再看一个例子。

//抽象工厂类
public abstract class AbstractFactory {
    public abstract Vehicle createVehicle();
    public abstract Weapon createWeapon();
    public abstract Food createFood();
}
//具体工厂类,其中Food,Vehicle,Weapon是抽象类,
public class DefaultFactory extends AbstractFactory{
    @Override
    public Food createFood() {
        return new Apple();
    }
    @Override
    public Vehicle createVehicle() {
        return new Car();
    }
    @Override
    public Weapon createWeapon() {
        return new AK47();
    }
}
//测试类
public class Test {
    public static void main(String[] args) {
        AbstractFactory f = new DefaultFactory();
        Vehicle v = f.createVehicle();
        v.run();
        Weapon w = f.createWeapon();
        w.shoot();
        Food a = f.createFood();
        a.printName();
    }
}

这段代码比较简单,没有很复杂的逻辑关系,应该比较好懂。

3.适配器模式

适配器模式也成为变压器模式,它是把一个类的接口转换成客户端指望的另外一个接口,从而使本来因接口不匹配而没法一块儿工做的两个类可以一块儿工做,适配类能够根据所传递的参数返还一个合适的实例给客户端。

模式中的角色:

目标接口(Target):客户所期待的接口。目标能够是具体的或抽象的类,也能够是接口。

须要适配的类(Adaptee):须要适配的类或适配者类。

适配器(Adapter):经过包装一个须要适配的对象,把原接口转换成目标接口。

好比,如今系统里已经实现了点、线和正方形,而如今客户须要一个圆形,通常的方法是创建一个Circle类来继承Shape类,而后去实现对应的display、fill等方法。但若是此时发现其余项目组其余人已经实现了一个画圆的类,可是他的方法名却和本身不同(为displayhh,fillhh),则不能直接使用这个类(由于正方形等类都是继承的Shape,display、fill是对shape方法的override,方法名不同不行,必须保证多态性,即继承的多态性)。此时要是从新写这个类就显得很愚蠢(本例中的Circle类简单,但实际中每每会遇到很复杂的类,真要重写,真是呵呵了)。在上述例子中目标接口即为须要的Circle类,须要适配的类就是已经有的画圆的类。具体看个图和看个例子。

适配器模式的代码实现
/// <summary>
    /// 定义客户端期待的接口
    /// </summary>
    public class Target
    {
        /// <summary>
        /// 使用virtual修饰以便子类能够重写
        /// </summary>
        public virtual void Request()
        {
            Console.WriteLine("This is a common request");
        }
    }

    /// <summary>
    /// 定义须要适配的类
    /// </summary>
    public class Adaptee
    {
        public void SpecificRequest()
        {
            Console.WriteLine("This is a special request.");
        }
    }

    /// <summary>
    /// 定义适配器
    /// </summary>
    public class Adapter extends Target
    {
        // 创建一个私有的Adeptee对象
        private Adaptee adaptee = new Adaptee();

        /// <summary>
        /// 经过重写,表面上调用Request()方法,变成了实际调用SpecificRequest()
        /// </summary>
       @Override
        public void Request()
        {
            adaptee.SpecificRequest();
        }
    }




客户端代码

   public class Program
    {
        public static void main(string[] args)
        {
            // 对客户端来讲,调用的就是Target的Request()
            Target target = new Adapter();
            target.Request();

            Console.Read();
        }
    }

Circle的例子和这个也是差很少的,具体就不给了,少年们本身去实现吧。

相关文章
相关标签/搜索