工廠
工廠模式主要是爲了解耦,A類想要調用B類,但是實例化B對象比較複雜,所以我們就把B對象的創建放到工廠裏面統一管理。由於B對象的創建已經統一了起來,所以即使業務邏輯發生變化,我們也只需要修改工廠類,而不需要尋找每個創建B對象的地方去修改。
例如,我們項目可能會使用多個數據庫源,但是他們的JDBC配置是不同的,所以我們就可以使用工廠模式來統一,也減少了使用者出錯的概率。
使用場景:
精確數據計算,獲取Jdbc連接,或者類似的通訊連接
實現:
簡單工廠:
首先創建一個接口
public interface Operation {
public double getResult(double numberA,double numberB) throws Exception;
}
然後是加減乘除的實現類
public class Add implements Operation{
// 加法計算
public double getResult(double numberA, double numberB) {
return numberA + numberB;
}
}
// 減 Sub
// 乘 Mul
// 除 Div
然後是簡單工廠
public class EasyFactory {
// 簡單工廠,根據字符串創建相應的對象
public static Operation createOperation(String name) {
Operation operationObj = null;
switch (name) {
case "+":
operationObj = new Add();
break;
case "-":
operationObj = new Sub();
break;
case "*":
operationObj = new Mul();
break;
case "/":
operationObj = new Div();
break;
}
return operationObj;
}
}
調用:
public class Client {
public static void main(String[] args) throws Exception {
Operation add = EasyFactory.createOperation("+");
Operation sub = EasyFactory.createOperation("-");
Operation mul = EasyFactory.createOperation("*");
Operation div = EasyFactory.createOperation("/");
System.out.println(add.getResult(1, 1));
System.out.println(sub.getResult(1, 1));
System.out.println(mul.getResult(1, 1));
System.out.println(div.getResult(1, 1));
}
}
工廠模式
工廠方法模式是對簡單工廠模式進一步的解耦,因爲在工廠方法模式中是一個子類對應一個工廠類,而這些工廠類都實現於一個抽象接口。這相當於是把原本會因爲業務代碼而龐大的簡單工廠類,拆分成了一個個的工廠類,這樣代碼就不會都耦合在同一個類裏了。
實現:
首先定義工廠接口:
import com.ljy.Mode.Operation;
public interface Factory {
public Operation createOperation() ;
}
然後是工廠實現類
// 加法類工廠
public class AddFactory implements Factory{
public Operation createOperation() {
System.out.println("加法運算");
return new Add();
}
}
// 減法類工廠
public class SubFactory implements Factory{
public Operation createOperation() {
System.out.println("減法運算");
return new Sub();
}
}
........
調用:
public class Client {
public static void main(String[] args) throws Exception {
// 使用反射機制實例化工廠對象,因爲字符串是可以通過變量改變的
Factory addFactory = (Factory) Class.forName("com.ljy.mode.factory.AddFactory").newInstance();
Factory subFactory=(Factory) Class.forName("com.ljy.mode.factory.SubFactory").newInstance();
// 通過工廠對象創建相應的實例對象
Operation add = addFactory.createOperation();
Operation sub = subFactory.createOperation();
System.out.println(add.getResult(1, 1));
System.out.println(sub.getResult(1, 1));
}
}
抽象工廠模式
抽象工廠與工廠方法模式的區別在於:抽象工廠是可以生產多個產品的,它圍繞一個超級工廠創建其他工廠。該超級工廠又稱爲其他工廠的工廠。
說白了,就是創建一個抽象工廠,然後建立其他工廠類實現。
實現就不寫了 有點麻煩,以後補充。
單例
單例設計模式,就是有一個準則,那就是只有一個對象被創建!!!,而且單例也是最簡單的設計模式了
單例模式的作用很明顯,首先,節省內存,因爲我只有一個對象,其次,我能保證數據的唯一性。
爲了保證對象唯一性,所以我們首先要確定構造方法的私有性,這樣的話就不能通過new的方式創建對象了,然後我們可以在內部創建自身對象,但是對象必須是私有的,然後,我們需要一個靜態的公開的方法,來讓外部類獲取對象。
餓漢模式
餓漢,一直在叫着“我好餓啊”,啥都想吃,所以,這種設計模式,是在一開始就已經把對象創建好了,但是,會造成內存浪費啊,就算沒用到他,也會在哪裏佔着浪費內存。
public class Singleton {
private static Singleton instance = new Singleton();
private Singleton (){}
public static Singleton getInstance() {
return instance;
}
}
懶漢模式
懶漢啥樣的,那當然是懶啊,所以懶漢模式,就意味着,只有等到需要這個對象的時候,纔回去創建對象
public class Singleton {
private static Singleton instance;
private Singleton (){}
public static Singleton getInstance() {
if (instance == null) {
instance = new Singleton();
}
return instance;
}
}
但是這種設計模式,有個很大的缺點,那就是線程不安全!!!一旦多個線程同時進來,那就會創建多個對象,違反我們的原則了。
那要是線程不安全咋辦呢,簡單啊,那就加鎖唄。
餓漢模式(同步方法)
public class Singleton {
private static Singleton singleton;
private Singleton (){}
public static synchronized Singleton getSingleton() {
if (singleton == null) {
singleton = new Singleton();
}
return singleton;
}
}
但是加鎖一時爽,效率太差了啊,那麼多線程都在方法外面等着呢啊
餓漢模式(雙重檢查)
既然加鎖方法會造成效率低下,那咱們就把加鎖的位置改一下吧,放在方法裏面
public class Singleton {
private static Singleton singleton;
private Singleton (){}
public static synchronized Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
但是,一想想,不對啊 這樣還是會造成線程不安全啊,導致出現兩個對象啊,不行不行,那咋辦呢 要不再加個鎖?可是鎖加在哪裏呢?
餓漢模式(雙重鎖)
於是,我們就加了個鎖,將這個鎖加載了聲明對象的時候,使用了volatile,這個版本也是非常完美的版本的,面試推薦哦
public class Singleton {
private volatile static Singleton singleton;
private Singleton (){}
public static Singleton getSingleton() {
if (singleton == null) {
synchronized (Singleton.class) {
if (singleton == null) {
singleton = new Singleton();
}
}
}
return singleton;
}
}
那麼我們總想着懶漢餓漢,是不是還有其他方式呢(注意,上面任意一種方式,都是無法阻止反射的!!!或者通過序列化 ,我們也是可以獲得兩個對象),其實是有的,那就是枚舉,枚舉是天生的單例,而且可以阻止反射哦
枚舉
public enum EnumSingleton {
INSTANCE;
public EnumSingleton getInstance(){
return INSTANCE;
}
}
看,是不是,非常簡單,代碼量也很少
裝飾器
裝飾器模式的定義是允許向一個現有的對象添加新的功能,同時又不改變其結構。就像是,我下個單,中間可能會有打折,可能會有運費,價格就會變動,所以我們就可以通過裝飾器模式來實現。
至於實現的話,其實也是主要靠繼承與子類重寫父類方法的原理來實現
首先一個接口是肯定的了:
public interface Component {
public void biu();
}
然後接口實現類:
public class ConcretComponent implements Component {
public void biu() {
System.out.println("biubiubiu");
}
}
接下來是裝飾器的接口:
//裝飾類
public class Decorator implements Component {
public Component component;
public Decorator(Component component) {
this.component = component;
}
public void biu() {
this.component.biu();
}
}
最後就是裝飾器接口實現類:
//具體裝飾類
public class ConcreteDecorator extends Decorator {
public ConcreteDecorator(Component component) {
super(component);
}
public void biu() {
System.out.println("fire in the hole");
this.component.biu();
}
}
說白了是不是感覺很簡單的,不就是多態麼。
具體調用是這樣的:
public class Client {
public static void main(String[] args) {
//使用裝飾器
Component component = new ConcreteDecorator(new ConcretComponent());
component.biu();
}
}
代理
代理,一說起代理我們就可以聯想到代理商,代理商幹嘛的,那不就是幫助別人做事的麼,例如什麼獵頭啊,中介啊,類似的,都是代理的體現。而且我們還可以藉助代理類再次增加一些功能,而不需要修改原有代碼。符合開閉原則。
至於到項目開發中,我們總會遇見一些事情,是我們不想讓我們的實現類實現的,例如,日誌啊,緩存啊,我們想在這個實現類執行的前後執行另外的一些操作,這就用到了我們的代理模式了。
同時代理模式和裝飾器模式是不一樣的!!!。
裝飾器模式和代理模式的區別:
裝飾器模式關注於在一個對象上動態的添加方法,然而代理模式關注於控制對對象的訪問。換句話 說,用代理模式,代理類(proxy class)可以對它的客戶隱藏一個對象的具體信息。因此,當使用代理模式的時候,我們常常在一個代理類中創建一個對象的實例。並且,當我們使用裝飾器模 式的時候,我們通常的做法是將原始對象作爲一個參數傳給裝飾者的構造器。
代理分爲靜態代理和動態代理。
靜態代理
靜態代理是在運行前,代理類的class文件就已經創建好了。但是呢,靜態代理也有缺點,我們得爲每一個服務都得創建代理類,工作量太大,不易管理。同時接口一旦發生改變,代理類也得相應修改。
首先是接口:
package com.ljy.util.designMode.proxy;
public interface BuyHouse {
void buyHosue();
}
然後是實現類:
package com.ljy.util.designMode.proxy;
public class BuyHouseImpl implements BuyHouse {
@Override
public void buyHosue() {
System.out.println("我要買房");
}
}
然後就是靜態代理類:
package com.ljy.util.designMode.proxy;
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("買房後裝修");
}
}
最後是測試類:
package com.ljy.util.designMode.proxy;
public class ProxyTest {
public static void main(String[] args) {
BuyHouse buyHouse = new BuyHouseImpl();
buyHouse.buyHosue();
BuyHouseProxy buyHouseProxy = new BuyHouseProxy(buyHouse);
buyHouseProxy.buyHosue();
}
}
動態代理
動態代理是在程序運行時通過反射機制動態創建的。
在動態代理中我們不再需要再手動的創建代理類,我們只需要編寫一個動態處理器就可以了。真正的代理對象由JDK再運行時爲我們動態的來創建。
首先讓我們創建動態代理類:
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* JDKDynamicProxy
* jdkd動態代理
*
* @author
* @create 2018-03-29 16:17
**/
public class JDKDynamicProxy implements InvocationHandler { // 一定要實現這個類哦
private Object target;
public JDKDynamicProxy(Object target) {
this.target = target;
}
/**
* 獲取被代理接口實例對象
* @param <T>
* @return
*/
public <T> T getProxy() {
return (T) Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.println("買房前準備");
Object result = method.invoke(target, args);
System.out.println("買房後準備");
return result;
}
}
然後就是測試類:
package com.ljy.util.designMode.proxy.dynamic;
import com.ljy.util.designMode.proxy.BuyHouse;
import com.ljy.util.designMode.proxy.BuyHouseImpl;
/**
* Client
* client測試代碼
**/
public class Client {
public static void main(String[] args) {
// 將JDK動態代理生成的class文件保存到本地
// System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles", "true");
// System.getProperties().put("jdk.proxy.ProxyGenerator.saveGeneratedFiles", "true"); // 或者是這個
// jdk動態代理測試
BuyHouse buyHouse = new JDKDynamicProxy(new BuyHouseImpl()).getProxy();
buyHouse.buyHosue();
}
}
是不是,只需要一個動態代理類就可以實現了,還不需要針對每個實現類開發。
未完待續。。。