天天看點

java工廠,代理,單例設計模式及其部分改善

java基礎要求掌握三種重點設計模式:工廠,代理,單例。本文将針對工廠設計模式中的簡單工廠模式,代理模式和單例模式這幾塊兒,我今天必須給大家講的明明白白!

一.工廠設計模式.

1.簡單工廠模式

簡單工廠模式專門定義一個類用來建立其他類的執行個體,被建立的執行個體通常都具有共同的父類。

概要:1.一個抽象産品類

           2.具體産品類

           3.一個工廠

優點:簡單易于實作,把類的執行個體化交給工廠,易于解耦。

缺點:添加具體産品需要修改工廠違反OCP開放封閉原則

以下是簡單工廠模式:

package com.matajie;

import java.util.Scanner;

/**
 * Author:年僅18歲的天才少年程式員
 * *******Java猛男丶Mata傑
 * *******我的程式才沒有BUG!!!
 */
interface Computer{
    void printComputer();
}
class MacComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a MacComputer");
    }
}
class SurComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a SurComputer");
    }
}
class Factory{
    public static Computer getInstance(String type){
        Computer computer = null;
        if(type.equals("MacComputer")){
            computer = new MacComputer();
        }else if (type.equals("SurComputer")){
            computer = new SurComputer();
        }else {
            System.out.println("無此商品");
        }
        return computer;
    }
}

public class Client {
    public void buyComputer(Computer computer){
        computer.printComputer();
    }

    public static void main(String[] args) {
        Client client = new Client();
        Scanner scanner = new Scanner(System.in);
        System.out.println("請輸入你想要的電腦");
        String type = scanner.nextLine();
        Computer computer = Factory.getInstance(type);
        client.buyComputer(computer);
    }
}
           

這種模式的缺點太過明顯了,每增加一個接口的子類就需要修改工廠類,在實際開發中根本用不到,那麼我們應該怎麼改進呢?

沒錯!用反射啊!因為Class類可以使用newInstance()執行個體化對象,而且Class.forName()能夠接收類名稱。

改進(反射):

package com.matajie;

import java.util.Scanner;

/**
 * Author:年僅18歲的天才少年程式員
 * *******Java猛男丶Mata傑
 * *******我的程式才沒有BUG!!!
 */
interface Computer{
    void printComputer();
}
class MacComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a MacComputer");
    }
}
class SurComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a SurComputer");
    }
}
class Factory{
    public static Computer getInstance(String type) throws ClassNotFoundException {
        Computer computer = null;
        try {
         Class<?> cls = Class.forName(type);//取得任意子類反射對象
            computer = (Computer) cls.newInstance();//通過反射取得執行個體化對象
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }
    return computer;
    }
}

public class Client {
    public static void main(String[] args) throws ClassNotFoundException {
        Computer computer =Factory.getInstance("com.matajie.MacComputer");
             computer.printComputer();
    }
}
           

這樣,我們就可以很友善的進行接口子類擴容

2.工廠方法模式.

定義一個用來建立對象的接口,讓子類決定執行個體化哪一個類。

概要

1. 一個抽象産品類

2. 多個具體産品類

3. 一個抽象工廠

4. 多個具體工廠 - 每一個具體産品對應一個具體工廠

優點:降低了代碼耦合度,對象的生成交給子類去完成

實作了開放封閉原則 - 每次添加子産品 不需要修改原有代碼

缺點:增加了代碼量,每個具體産品都需要一個具體工廠

當增加抽象産品 也就是添加一個其他産品族 需要修改工廠 違背OCP

package com.matajie;

import java.util.Scanner;

/**
 * Author:年僅18歲的天才少年程式員
 * *******Java猛男丶Mata傑
 * *******我的程式才沒有BUG!!!
 */
interface Computer{
    void printComputer();
}
class MacComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a MacComputer");
    }
}
class SurComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a SurComputer");
    }
}
interface ComputerFactory{
    Computer creataComputer();
}
class MacFactory implements ComputerFactory{

    @Override
    public Computer creataComputer() {
        return new MacComputer();
    }
}
class SurFactory implements ComputerFactory{

    @Override
    public Computer creataComputer() {
        return new SurComputer();
    }
}
public class Client{
    public void buyComputer(Computer computer){
        computer.printComputer();
    }

    public static void main(String[] args) {
        Client client = new Client();
        ComputerFactory factory = new MacFactory();
        client.buyComputer(factory.creataComputer());
    }
}
           

3.抽象工廠模式

抽象工廠模式就是在工廠方法模式上進行了擴充,它把原先的工廠方法模式中隻能有一個抽象産品不能添加産品族的缺點克服了

概要:1.多個抽象産品類

           2.具體産品類

           3.抽象工廠類聲明一組傳回抽象産品的方法

           4.具體工廠類生命一組具體産品

優點:代碼解耦

實作多個産品族(相關聯産品組成的家族),而工廠方法模式的單個産品,可以滿足更多的生産需求

很好的滿足OCP開放封閉原則

抽象工廠模式中我們可以定義實作不止一個接口,一個工廠也可以生成不止一個産品類 對于複雜對象的生産

相當靈活易擴充

缺點:擴充産品族相當麻煩 而且擴充産品族會違反OCP,因為要修改所有的工廠

由于抽象工廠模式是工廠方法模式的擴充 總體的來說很笨重。

package com.matajie;

import java.util.Scanner;

/**
 * Author:年僅18歲的天才少年程式員
 * *******Java猛男丶Mata傑
 * *******我的程式才沒有BUG!!!
 */
interface Computer{
    void printComputer();
}
class MacComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a MacComputer");
    }
}
class SurComputer implements Computer{

    @Override
    public void printComputer() {
        System.out.println("this is a SurComputer");
    }
}
interface OperatingSystem{
    void printSystem();
}
class MacOsSystem implements OperatingSystem{

    @Override
    public void printSystem() {
        System.out.println("this is a MacOsSystem");
    }
}
class Windows8System implements OperatingSystem{

    @Override
    public void printSystem() {
        System.out.println("this is a Windows8System");
    }
}
interface ProductionFactory{
    Computer createComputer();
    OperatingSystem createSystem();
}
class AppleFactory implements ProductionFactory{

    @Override
    public Computer createComputer() {
        return new MacComputer();
    }

    @Override
    public OperatingSystem createSystem() {
        return new MacOsSystem();
    }
}
class MsFactory implements ProductionFactory{

    @Override
    public Computer createComputer() {
        return new SurComputer();
    }

    @Override
    public OperatingSystem createSystem() {
        return new Windows8System();
    }
}
public class Client{
    public void buyComputer(Computer computer){
        computer.printComputer();
    }
    public void use(OperatingSystem system){
        system.printSystem();
    }

    public static void main(String[] args) {
        Client client = new Client();
        ProductionFactory factory = new AppleFactory();
        Computer computer = factory.createComputer();
        OperatingSystem system =factory.createSystem();
        client.buyComputer(computer);
        client.use(system);
    }
}
           

工廠設計模式總結:

簡單工廠模式最大的優點就是工廠内有具體的邏輯去判斷生成什麼産品,将類的執行個體化交給了工廠,這樣當

我們需要什麼産品隻需要修改工廠的調用而不需要去修改用戶端,對于用戶端來說降低了與具體産品的依賴

工廠方法模式是簡單工廠的擴充,工廠方法模式把原先簡單工廠中的實作那個類的邏輯判斷交給了用戶端,

如果像添加功能隻需要修改客戶和添加具體的功能,不用去修改之前的類。

抽象工廠模式進一步擴充了工廠方法模式,它把原先的工廠方法模式中隻能有一個抽象産品不能添加産品族

的缺點克服了,抽象工廠模式不僅僅遵循了OCP原則,而且可以添加更多産品(抽象産品),具體工廠也不僅僅

可以生成單一産品,而是生成一組産品,抽象工廠也是聲明一組産品,對應擴充更加靈活,但是要是擴充族

系就會很笨重。

二:代理模式與改進

兩個子類共同實作一個接口,其中一個子類負責真實業務實作,另外一個子類完成輔助真實業務主體的操作

package com.matajie;

import java.lang.reflect.Proxy;

/**
 * Author:年僅18歲的天才少年程式員
 * *******java猛男丶Mata傑
 * *******我的程式才沒有BUG!!!
 */
interface ISubject{
    void buyComputer();
}
class RealSubject implements ISubject{

    @Override
    public void buyComputer() {
        System.out.println("買電腦");
    }
}
class ProxySubject implements ISubject{
    private ISubject subject;
    public ProxySubject(ISubject subject){
        this.subject =subject;
    }
    public void produceComputer(){
        System.out.println("生産電腦");
    }
    public void afterSafe(){
        System.out.println("售後");
    }
    @Override
    public void buyComputer() {
          this.produceComputer();
          this.subject.buyComputer();//調用真實業務
          this.afterSafe();
    }
}
class Factory{
    public static ISubject getInstance(){
        return new ProxySubject(new RealSubject());
    }
}
public class Test {
    public static void main(String[] args) {
        ISubject subject =Factory.getInstance();
        subject.buyComputer();
    }
}
           

這種代理模式隻能夠代理一個接口的子類對象,無法代理更多的接口子類對象。那麼怎麼解決呢?

動态代理模式:

一個代理類可以代理所有需要被代理的接口的子類對象

interface ISubject{
    public void printComputer(String msg,int num);
}
class RealSubject implements ISubject{

    @Override
    public void printComputer(String msg, int num) {
        System.out.println("我想買個"+num+"元的"+msg);
    }
}
class ProxySubject implements InvocationHandler{
      private Object target;//綁定任意的接口對象,使用Object描述
      public Object bind(Object target){//實作真實對象的綁定處理,同時傳回代理對象
          this.target =target;//儲存真實對象
          return Proxy.newProxyInstance(target.getClass().getClassLoader(),target.getClass().getInterfaces(),this);
      }//傳回一個代理對象(這個對象是根據接口定義動态建立生成的代理對象)
      public void preHandle(){
          System.out.println("[ProxySubject]方法處理前");
      }
      public void afterHandle(){
          System.out.println("[afterSubject]方法處理後");
      }
    @Override
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        this.preHandle();
        Object ret = method.invoke(this.target,args);//反射調用方法
        this.afterHandle();
        return ret;
    }
}
public class Test{
    public static void main(String[] args) {
        ISubject subject = (ISubject) new ProxySubject().bind(new RealSubject());
        subject.printComputer("蘋果電腦",8000);
    }
}

           

三.單例模式的8種寫法(這裡不對不安全單例做說明)

單例模式:一個類隻允許産生一個執行個體化對象,構造方法私有化。

1.餓漢式(普通)單例:(線程安全,可用)

public class Singleton {
    private final static Singleton INSTANCE = new Singleton();
    private Singleton(){}
    public static Singleton getInstance(){
        return INSTANCE;
    }
}
           

2.餓漢式(靜态代碼塊)(線程安全,可用)

public class Singleton{
    private static Singleton instance;
    static {
        instance = new Singleton();
    }
    private Singleton(){}
    public static Singleton getInstance(){
        return instance;
    }
}
           

3.雙重檢查(線程安全,建議用)

public class Singleton{
    private static volatile Singleton singleton;
    private Singleton(){}
    public static Singleton getSingleton(){
        if(singleton == null){
            synchronized (Singleton.class){
                if(singleton == null){
                    singleton = new Singleton();
                }
            }
        }
        return singleton;
    }
}
           

4.靜态内部類(線程安全,建議用)

public class Singleton{
    private Singleton(){}
    public static class SingletonInstance{
        private static final Singleton INSTANCE = new Singleton();
    }
    public static Singleton getInstance(){
        return SingletonInstance.INSTANCE;
    }
}
           

5.枚舉(極推薦用)

public enum Singleton{
    INSTANCE;
    public void method(){
        
    }
}
           

有哪裡可以改進的地方希望大家多多指教。