1. 程式人生 > 實用技巧 >LeetCode #1013. Partition Array Into Three Parts With Equal Sum

LeetCode #1013. Partition Array Into Three Parts With Equal Sum

設計模式

概述:

  • 建立型模式:
    • 單例模式、工廠模式、抽象工廠模式、建造者模式、原型模式
  • 結構型模式:
    • 介面卡模式、橋接模式、裝飾模式、組合模式、外觀模式、享元模式、代理模式
  • 行為型模式:
    • 模板方法模式、命令模式、迭代器模式、觀察者模式、中介者模式、備忘錄模式、直譯器模式、狀態模式、策略模式、職責鏈模式、訪問者模式

OOP的七大原則

  • 開閉原則:對擴充套件開放,對修改關閉
  • 里氏替換原則:繼承必須確保超類所擁有的性質在子類中仍然成立,儘量不要去破壞繼承關係
  • 依賴倒置原則:面向介面程式設計,不要面向現實程式設計
  • 單一職責原則:控制類的粒度大小,將物件解耦,提高其內聚性。實現類要職責單一
  • 介面隔離原則:要為各個類建立它們所需要的專用介面
  • 迪米特法則:只與你的直接朋友交談,不跟“陌生人”說話。降低物件之間的耦合度
  • 合成複用原則:儘量先使用組合或者聚合等關聯關係來實現,其次才考慮使用繼承關係來實現。

1、單例模式

意圖:保證一個類僅有一個例項,並提供一個訪問它的全域性訪問點。

主要解決:一個全域性使用的類的頻繁地建立與銷燬。

關鍵程式碼:建構函式是私有的。

餓漢式:

public class singleton{
    private singleton(){}
    private static singleton singlet=new singleton();
    public static singleton getSingleton(){
        return singlet;
    }
}

它基於classloader機制避免了多執行緒的同步問題,解決了多執行緒安全問題,但這種方式浪費記憶體。沒有初始化Lazy

懶漢式:

public class Singleton{
    private Singleton(){}
    private static Singleton sing;
    public static Singleton getSingleton(){
        if(sing==null){
            sing=new Singleton();
        }
        return sing;
    }
}

因為沒有加鎖synchronized,多執行緒下不安全,初始化了Lazy

加鎖後的懶漢式:

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

雙重校驗鎖:

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

執行緒安全,初始化了Lazy

靜態內部類:

public class Singleton{
    private static class sing{
        private static final Singleton SING=new Singleton();
    }
    private Singleton(){}
    public static final Singleton getSingleton(){
        return sing.SING;
    }
}

執行緒安全,初始化了Lazy,這種方式能達到雙重校驗的一樣的功效。

列舉:

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

執行緒安全,沒有初始化Lazy,不能通過反射來呼叫該類的私有函數了,列舉中只有引數為(sting.class,int.class)構造器。因此,通過反射獲取不到列舉的例項。

2、工廠模式

意圖:定義一個建立物件的介面,讓其子類自己決定例項化哪一個工廠類,工廠模式使其建立過程延遲到子類進行。

主要解決:主要解決介面選擇問題。

關鍵程式碼:建立過程在其子類執行。

public interface Shape {
   void draw();
}
public class Rectangle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Rectangle::draw() method.");
   }
}
public class Square implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Square::draw() method.");
   }
}
public class Circle implements Shape {
 
   @Override
   public void draw() {
      System.out.println("Inside Circle::draw() method.");
   }
}
public class ShapeFactory {
    
   //使用 getShape 方法獲取形狀型別的物件
   public Shape getShape(String shapeType){
      if(shapeType == null){
         return null;
      }        
      if(shapeType.equalsIgnoreCase("CIRCLE")){
         return new Circle();
      } else if(shapeType.equalsIgnoreCase("RECTANGLE")){
         return new Rectangle();
      } else if(shapeType.equalsIgnoreCase("SQUARE")){
         return new Square();
      }
      return null;
   }
}
public class FactoryPatternDemo {
 
   public static void main(String[] args) {
      ShapeFactory shapeFactory = new ShapeFactory();
 
      //獲取 Circle 的物件,並呼叫它的 draw 方法
      Shape shape1 = shapeFactory.getShape("CIRCLE");
 
      //呼叫 Circle 的 draw 方法
      shape1.draw();
 
      //獲取 Rectangle 的物件,並呼叫它的 draw 方法
      Shape shape2 = shapeFactory.getShape("RECTANGLE");
 
      //呼叫 Rectangle 的 draw 方法
      shape2.draw();
 
      //獲取 Square 的物件,並呼叫它的 draw 方法
      Shape shape3 = shapeFactory.getShape("SQUARE");
 
      //呼叫 Square 的 draw 方法
      shape3.draw();
   }
}
//執行程式,輸出的結果
Inside Circle::draw() method.
Inside Rectangle::draw() method.
Inside Square::draw() method.

3、抽象工廠模式

意圖:提供一個建立一系列相關或相互依賴物件的介面,而無需指定他們具體的類。

主要解決:主要解決介面選擇問題。

關鍵程式碼:在一個工廠裡聚合多個同類產品。

手機、路由器的介面

package shejimoshi.abstactor;

public interface PhoneProduct {
    void start();
    void close();
    void daphone();
    void sendSm();
}
package shejimoshi.abstactor;

public interface RouterProduct {
    void start();
    void close();
    void openWifi();
    void setting();
}

小米、華為手機,小米、華為路由器的實現類

package shejimoshi.abstactor;
//小米手機
public class xiaomiPhone implements PhoneProduct {
    public void start() {
        System.out.println("小米手機開機");
    }

    public void close() {
        System.out.println("小米手機關機");
    }

    public void daphone() {
        System.out.println("用小米手機打電話");
    }

    public void sendSm() {
        System.out.println("用小米手機發簡訊");
    }
}
package shejimoshi.abstactor;
//小米路由器
public class xiaomiRouter implements RouterProduct {
    public void start() {
        System.out.println("小米路由器開機");
    }

    public void close() {
        System.out.println("小米路由器關機");
    }

    public void openWifi() {
        System.out.println("小米路由器開啟wifi");
    }

    public void setting() {
        System.out.println("設定小米路由器");
    }
}
package shejimoshi.abstactor;
//華為手機
public class huaweiPhone implements PhoneProduct {
    public void start() {
        System.out.println("華為手機開機了");
    }

    public void close() {
        System.out.println("華為手機關機了");
    }

    public void daphone() {
        System.out.println("用華為手機打電話");
    }

    public void sendSm() {
        System.out.println("用華為手機發簡訊");
    }
}
package shejimoshi.abstactor;
//華為路由器
public class huaweiRouter implements RouterProduct {
    public void start() {
        System.out.println("華為路由器開機了");
    }

    public void close() {
        System.out.println("華為路由器關機了");
    }

    public void openWifi() {
        System.out.println("華為路由器打開了wifi");
    }

    public void setting() {
        System.out.println("設定華為路由器");
    }
}

這時,建立一個工廠介面,管理手機、路由器的生產

package shejimoshi.abstactor;

public interface Factory {
    PhoneProduct Phone();
    RouterProduct router();
}

小米,華為工廠的實現類

package shejimoshi.abstactor;
//小米生產工廠
public class xiaomiFactory implements Factory {
    public PhoneProduct Phone() {
        return new xiaomiPhone();
    }

    public RouterProduct router() {
        return new xiaomiRouter();
    }
}
package shejimoshi.abstactor;
//華為生產工廠
public class huaweiFactory implements Factory {
    public PhoneProduct Phone() {
        return new huaweiPhone();
    }

    public RouterProduct router() {
        return new huaweiRouter();
    }
}

測試

package shejimoshi.abstactor;

public class consumer {
    public static void main(String[] args) {
        System.out.println("================小米系列===================");
        xiaomiFactory xiaomiFactory = new xiaomiFactory();
        PhoneProduct phone = xiaomiFactory.Phone();
        phone.daphone();
        phone.sendSm();
        RouterProduct router = xiaomiFactory.router();
        router.openWifi();
        router.setting();
        System.out.println("==================華為系列====================");
        huaweiFactory huaweiFactory = new huaweiFactory();
        PhoneProduct phone1 = huaweiFactory.Phone();
        phone1.daphone();
        phone1.sendSm();
        RouterProduct router1 = huaweiFactory.router();
        router1.openWifi();
        router1.setting();
    }
}

輸出結果:

================小米系列===================
用小米手機打電話
用小米手機發簡訊
小米路由器開啟wifi
設定小米路由器
==================華為系列====================
用華為手機打電話
用華為手機發簡訊
華為路由器打開了wifi
設定華為路由器

4、建造者模式

意圖:將一個複雜的構建與其表示相分離,使得同樣的構建過程可以建立不同的表示。

主要解決:主要解決在軟體系統中,有時候面臨著“一個複雜物件”的建立工作,其通常由各個部分的子物件用一定的演算法構成;由於需求的變化,這個複雜物件的各個部分經常面臨著劇烈的變化,但是將它們組合在一起的演算法卻相對穩定。

關鍵程式碼:建造者:建立和提供例項,導演:管理建造出來的例項的依賴關係。

實現:

package shejimoshi.builder;
//抽象建造者
public abstract class Builder {
    abstract void builderA();
    abstract void builderB();
    abstract void builderC();
    abstract void builderD();

    abstract  Product getProduct();
}
package shejimoshi.builder;
//被建造的物件、產品
public class Product {
    private String builderA;
    private String builderB;
    private String builderC;
    private String builderD;

    public String getBuilderA() {
        return builderA;
    }

    public void setBuilderA(String builderA) {
        this.builderA = builderA;
    }

    public String getBuilderB() {
        return builderB;
    }

    public void setBuilderB(String builderB) {
        this.builderB = builderB;
    }

    public String getBuilderC() {
        return builderC;
    }

    public void setBuilderC(String builderC) {
        this.builderC = builderC;
    }

    public String getBuilderD() {
        return builderD;
    }

    public void setBuilderD(String builderD) {
        this.builderD = builderD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "builderA='" + builderA + '\'' +
                ", builderB='" + builderB + '\'' +
                ", builderC='" + builderC + '\'' +
                ", builderD='" + builderD + '\'' +
                '}';
    }
}
package shejimoshi.builder;
//具體的建造者,工人
public class worker extends Builder {
    private Product product;

    public worker() {
        product=new Product();
    }

    void builderA() {
        product.setBuilderA("地基");
        System.out.println(product.getBuilderA());
    }

    void builderB() {
        product.setBuilderB("鋪鋼筋");
        System.out.println(product.getBuilderB());
    }

    void builderC() {
        product.setBuilderC("砌牆");
        System.out.println(product.getBuilderC());
    }

    void builderD() {
        product.setBuilderD("粉刷");
        System.out.println(product.getBuilderD());
    }

    Product getProduct() {
        return product;
    }
}
package shejimoshi.builder;
//指揮:核心,負責指揮構建一個工程,工程如何構建,由它決定
public class Dirdest {
    public Product builder(Builder builder){
        builder.builderA();
        builder.builderD();
        builder.builderB();
        builder.builderC();
        return  builder.getProduct();
    }
}
package shejimoshi.builder;

public class test {
    public static void main(String[] args) {
        Dirdest dirdest = new Dirdest();
        Product builder = dirdest.builder(new worker());
        System.out.println(builder.toString());
    }
}

第二種實現方式:

package shejimoshi.builder.demo2;
//抽象的建造者
public abstract class Builder {
    abstract Builder builderA(String msg);
    abstract Builder builderB(String msg);
    abstract Builder builderC(String msg);
    abstract Builder builderD(String msg);
    abstract Product getProduct();
}
package shejimoshi.builder.demo2;
//產品
public class Product {
    private String builderA="漢堡";
    private String builderB="炸雞";
    private String builderC="雞肉卷";
    private String builderD="可樂";

    public String getBuilderA() {
        return builderA;
    }

    public void setBuilderA(String builderA) {
        this.builderA = builderA;
    }

    public String getBuilderB() {
        return builderB;
    }

    public void setBuilderB(String builderB) {
        this.builderB = builderB;
    }

    public String getBuilderC() {
        return builderC;
    }

    public void setBuilderC(String builderC) {
        this.builderC = builderC;
    }

    public String getBuilderD() {
        return builderD;
    }

    public void setBuilderD(String builderD) {
        this.builderD = builderD;
    }

    @Override
    public String toString() {
        return "Product{" +
                "builderA='" + builderA + '\'' +
                ", builderB='" + builderB + '\'' +
                ", builderC='" + builderC + '\'' +
                ", builderD='" + builderD + '\'' +
                '}';
    }
}
package shejimoshi.builder.demo2;
//具體的建造者,同時兼指揮,可以改變建造事物,builderA....
public class worker extends Builder {
    private Product product;

    public worker() {
        product=new Product();
    }

    Builder builderA(String msg) {
        product.setBuilderA(msg);
        return this;
    }

    Builder builderB(String msg) {
        product.setBuilderB(msg);
        return this;
    }

    Builder builderC(String msg) {
        product.setBuilderC(msg);
        return this;
    }

    Builder builderD(String msg) {
        product.setBuilderD(msg);
        return this;
    }

    Product getProduct() {
        return product;
    }
}
package shejimoshi.builder.demo2;

public class test {
    public static void main(String[] args) {
        worker worker = new worker();
        Product product = worker.builderA("全家桶").builderD("雪碧").getProduct();
        System.out.println(product.toString());
    }
}

5、原型模式

意圖:用原型例項指定建立物件的種類,並且通過拷貝這些原型建立新的物件

主要解決:在執行期建立和刪除原型

關鍵程式碼:利用已有的一個原型物件,快速地生成和原型物件一樣的例項

實現:淺拷貝

package shejimoshi.propotry;

import java.util.Date;

public class Bilibili implements Cloneable {
    private String name;
    private Date Datetime;

    @Override
    protected Object clone() throws CloneNotSupportedException {
        return super.clone();
    }

    public Bilibili() {
    }

    public Bilibili(String name, Date datetime) {
        this.name = name;
        Datetime = datetime;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public Date getDatetime() {
        return Datetime;
    }

    public void setDatetime(Date datetime) {
        Datetime = datetime;
    }

    @Override
    public String toString() {
        return "Bilibili{" +
                "name='" + name + '\'' +
                ", Datetime=" + Datetime +
                '}';
    }
}
package shejimoshi.propotry;

import java.util.Date;

public class Test {
    public static void main(String[] args) throws CloneNotSupportedException {
        Date date = new Date();
        Bilibili v1 = new Bilibili("鹿鼎記", date);
        System.out.println("v1==>"+v1);
        System.out.println(v1.hashCode());
        Bilibili v2 = (Bilibili) v1.clone();
        System.out.println("v2==>"+v2);
        System.out.println(v2.hashCode());
    }
}
v1==>Bilibili{name='鹿鼎記', Datetime=Mon Nov 23 19:55:07 CST 2020}
1836019240
v2==>Bilibili{name='鹿鼎記', Datetime=Mon Nov 23 19:55:07 CST 2020}
325040804

深拷貝:

重寫了clone方法,把重寫後的例項也指向了date類

 @Override
    protected Object clone() throws CloneNotSupportedException {
        Bilibili o = (Bilibili) super.clone();
        o.setDatetime(new Date());
        return o ;
    }

6、介面卡模式

意圖:將一個類的介面轉換成客戶希望的另外一個介面。介面卡模式使得原本由於介面不相容而不能一起工作的那些類可以一起工作。

主要解決:主要解決在軟體系統中,常常要將一些“現存的物件”放到新的環境中,而新環境要求的介面是現物件不能滿足的。

關鍵程式碼:介面卡繼承或依賴已有的物件,實現想要的介面。

實現:物件介面卡

package shejimoshi.adapter;
//網線
public class wangxian {
    public void Internal(){
        System.out.println("連線電腦上網");
    }
}
package shejimoshi.adapter;
//介面卡介面
public interface NetInterface {
    public void NetInter();
}
package shejimoshi.adapter;
//物件介面卡
public class adapter implements NetInterface {
    private wangxian w;

    public adapter(wangxian w) {
        this.w = w;
    }

    public void NetInter() {
        w.Internal();
    }
}
package shejimoshi.adapter;
//電腦及測試
public class computer {
    public void wantInternal(NetInterface netInterface){
                   netInterface.NetInter();
    }

    public static void main(String[] args) {
        computer computer = new computer();
        wangxian wangxian = new wangxian();
        adapter adapter = new adapter(wangxian);
        computer.wantInternal(adapter);
    }
}

實現二:類介面卡

package shejimoshi.adapter;

public class adapter extends wangxian implements NetInterface {

    public void NetInter() {
        super.Internal();
    }
}

7、橋接模式

意圖:將抽象部分與實現部分分離,使得它們都可以獨立的變化。

主要解決:在有多種可能會變化的情況下,用繼承會造成類爆炸問題,擴充套件起來不靈活。

關鍵程式碼:抽象類依賴實現類

實現:

package shejimoshi.bridge;
//品牌介面
public interface brand {
    void info();
}
package shejimoshi.bridge;
//品牌實現類
public class Apple implements brand {
    public void info() {
        System.out.print("蘋果");
    }
}
package shejimoshi.bridge;

public class lenevo implements brand {
    public void info() {
        System.out.print("聯想");
    }
}
package shejimoshi.bridge;
//電腦抽象類
public abstract class computer {
    private brand brand;

    public computer(brand brand) {
        this.brand = brand;
    }

    protected void sout(){
        brand.info();
    }
}
package shejimoshi.bridge;
//抽象類的子類
public class Destkop extends computer {

    public Destkop(brand brand) {
        super(brand);
    }

    @Override
    protected void sout() {
        super.sout();
        System.out.println("臺式電腦");
    }
}
package shejimoshi.bridge;

public class bijiben extends computer {
    public bijiben(shejimoshi.bridge.brand brand) {
        super(brand);
    }

    @Override
    protected void sout() {
        super.sout();
        System.out.println("筆記本");
    }
}
package shejimoshi.bridge;
//測試
public class test {
    public static void main(String[] args) {
        //蘋果筆記本
        computer computer=new bijiben(new Apple());
        computer.sout();
        //聯想臺式電腦
        computer computer1=new Destkop(new lenevo());
        computer1.sout();
    }
}
//測試結果
蘋果筆記本
聯想臺式電腦

8、代理模式

意圖:為其他物件提供一種代理以控制對這個物件的訪問

主要解決:在直接訪問物件時帶來的問題,比如說:要訪問的物件在遠端的機器上。在面向物件系統中,有些物件由於某些原因(比如物件建立開銷很大,或者某些操作需要安全控制,或者需要程序外的訪問),直接訪問會給使用者或者系統結構帶來很多麻煩,我們可以在訪問此物件時加上一個對此物件的訪問層。

關鍵程式碼:實現與被代理類組合。

8.1靜態代理

package shejimoshi.proxy;
//租房介面
public interface Rent {
    void rent();
}
package shejimoshi.proxy;
//介面的實現類,房東要出租房子
public class Host implements Rent {
    public void rent() {
        System.out.println("房東要出租房子啦");
    }
}
package shejimoshi.proxy;
//代理物件,這裡使用的是組合
public class Proxy {
    private Host host;

    public Proxy(Host host) {
        this.host = host;
    }
    public void rent(){
        seehome();
        host.rent();
        hetong();
    }
    public void seehome(){
        System.out.println("中介帶你去看房子");
    }
    public void hetong(){
        System.out.println("要和中介籤合同了");
    }
}
package shejimoshi.proxy;
//使用者現實和代理物件租房子
public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        Proxy proxy = new Proxy(host);
        proxy.rent();
    }
}

8.2動態代理

關鍵使用proxy的newProxyInstance方法生成一個代理類,然後再呼叫中invocationHandler中的inovke方法實現代理類中的方法。

例項一:

package shejimoshi.proxy.demo02;

public interface Rent {
    void rent();
}
package shejimoshi.proxy.demo02;

public class Host implements Rent {
    public void rent() {
        System.out.println("房東要出租房子啦");
    }
}
package shejimoshi.proxy.demo02;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
//生成代理類的invocationHandler介面的實現類
public class ProxyInvokehandler implements InvocationHandler {

    private Rent rent;

    public ProxyInvokehandler(Rent rent) {
        this.rent = rent;
    }
     public Object getProxy(){
      return  Proxy.newProxyInstance(this.getClass().getClassLoader(),rent.getClass().getInterfaces(),this);
    }
    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        seeHouse();
        System.out.println("實現了"+method.getName()+"方法");
        Object obj = method.invoke(rent);
        return obj;
    }
    public void seeHouse(){
        System.out.println("中介要帶我去看房子啦");
    }
}
package shejimoshi.proxy.demo02;

public class Client {
    public static void main(String[] args) {
        Host host = new Host();
        ProxyInvokehandler proxyInvokehandler = new ProxyInvokehandler(host);
        Rent proxy = (Rent) proxyInvokehandler.getProxy();
        proxy.rent();
    }
}

例項二:

package shejimoshi.proxy.demo03;

public interface Service {
    void add();
    void delete();
    void update();
    void query();
}
package shejimoshi.proxy.demo03;

public class ServiceImpl implements Service {
    public void add() {
        System.out.println("添加了一個使用者");
    }

    public void delete() {
        System.out.println("刪除了一個使用者");
    }

    public void update() {
        System.out.println("修改了一個使用者");
    }

    public void query() {
        System.out.println("查詢了一個使用者");
    }
}
package shejimoshi.proxy.demo03;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class ProxyInvocationHandler implements InvocationHandler {
    private Service service;

    public void setService(Service service) {
        this.service = service;
    }
    public Object getProxy(){
        return Proxy.newProxyInstance(this.getClass().getClassLoader(),service.getClass().getInterfaces(),this);
    }

    public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
        Log(method.getName());
        Object obj = method.invoke(service);
        return obj;
    }
    public void Log(String msg){
        System.out.println("使用了"+msg+"方法");
    }
}
package shejimoshi.proxy.demo03;

public class Client {
    public static void main(String[] args) {
        ServiceImpl service = new ServiceImpl();
        ProxyInvocationHandler handler = new ProxyInvocationHandler();
        handler.setService(service);
        Service proxy = (Service) handler.getProxy();
        proxy.query();
    }
}