設計原則:
1、里氏替換原則(Liskov Substitution Principle):
此原則的思想是面對接口的編程中,我們要做到最大化的可擴展性和高內聚低耦合。在設計中,很有可能的問題是,一個功能對象類是無法滿足一個項目特定的業務需求。這個時候,如果在接口中引用的是某個功能類的父類對象,我們就可以在子類中繼承父類所有功能的同時並且擴展特定需求。在接口引入的地方,如果使用子類插入而不產生問題。這就是里氏替換原則。說到這裏,其中的子類功能增加的原則與下列所述的開閉原則是相對應的。所以,這些原則是相互作用的
2、單一原則(Single Responsibility Principle):
此原則的意義在於所有類的設計上,需要對功能進行劃分,這樣的好處是,形成單一變量,容易進行代碼的解耦。同時,功能分類使得每個類的作用是非常明確的。
3、依賴注入原則(Dependence Inversion Principle):
此原則的意義其實也是解耦。依賴其實就是一個映射關係。我們每次在其他功能接口中使用的是這個這個接口的名稱,即key值,至於這個key值所對應的value值,並不是外部引用着所要關心的事。這就造成了一種接口之間的無關性的假象。同時,在接口發生變動後,我們只需要對映射的鍵值對進行修改即可。在Java中所有interface的類,其實都有這種異曲同工之處。我們每次都只需要複寫這個接口,但是我們不關心這個接口裏,到底需要做什麼,當然,我們更希望,在接口中做一些我們雙方都約定好了的事情。接口,在編程中其實起到的是一種約束和協議的作用。如果繼承了一個接口,就是在完成這個接口在設計之初的一種規範。
同時,在提到依賴注入的同時,更應該聯繫到依賴反轉(控制反轉,Inversion of Control),在javaWeb中這是與依賴注入相互配套使用的。控制反轉的作用是是兩個接口之間原本相互依存的關係變成兩者都依賴於第三方容器。這樣也是爲了解耦。控制反轉只是一種概念,在這個前提下,我們要做的就是依賴的注入,每次使用鍵值對的思想,對類進行綁定,然後我們在使用的時候,只要引用key就可以了,而不用去關心value,並且,這是一個不需要new的過程。平常的時候,每次引用對象,我們都需要new一個對象。這很大程度上是依賴於這個引用者的操作控制。但是,在依賴注入後,就可控制反轉,我們直接從鍵值對中通過key的值來獲取一個value的對象。這樣產生對象的過程是在容器中產生的,而不關引用者什麼事了,這就完成了解耦。
4、接口分離原則(Interface Segregation Principle):
此原則,更像是一種協議上的規範。每次我們進行功能分析的時候,都能大概明白完成一個需求所要經歷的步驟爲幾何。或者兩個需求可能完成相似的動作。這時,我們把動作先以接口的方式實現出來,就會讓人看的一目瞭然,這是因爲,接口不需要實現具體的方法,把整個框架剝離出來。並且,對接口的修改,更是開閉原則的思想
5、迪米特原則(Law of Demeter):
此原則也是爲了解耦,因爲,如果在A類中要使用B類的功能動作,我們如果直接在A中new出這麼一個B類,就將A和B耦合起來了。而如果我們在第三方類或接口中同時實例化,A和B,然後在A中提供一個插入B的接口,不就達到解耦的效果了嗎
6、開閉原則(Open for Extension,Closed for Modification):
一個接口,如果不滿足需求,應該通過繼承的方式進行修改,而不是在本身的接口上修改
設計模式
1、簡單工廠模式:
我個人覺得,簡單工廠模式,其實就是一個解耦度不高的選擇模式,用來,實現父類對不同子類的調用。不過由於Api的子類個數不定,如果添加了子類的話,就需要修改工廠方法,這是一種不解耦的行爲。這時,又可以通過依賴注入的原則進行解耦。就是在工廠類所在的包下構建一個.Properties的文件,在文件中對Api所有子類進行描述,而後在工廠方法中通過流來載入這個內容,根據內容,產生相應的對象
應用場景:一個類的不確定生成哪個子類對象的時候,工廠模式,會根據類型進行選擇
public class SimpleFactoryModel {
public static Api api;
private SimpleFactoryModel() {
};
public static Api createApi(int type) {
if (type == 1) {
api = new Api1();
} else if (type == 2) {
api = new Api2();
} else if (type == 3) {
api = new Api3();
}
return api;
}
}
interface Api {
public void create();
}
class Api1 implements Api {
@Override
public void create() {
System.out.println("create Api 1");
}
}
class Api2 implements Api {
@Override
public void create() {
System.out.println("create Api 2");
}
}
class Api3 implements Api {
@Override
public void create() {
System.out.println("create Api 3");
}
}
2、(抽象)工廠模式:
我覺得抽象工廠模式,就是來改進簡單工廠模式的。思路是,把create()在抽象工廠中形成一個接口,每次結成這個接口,來實現不同子類的實例化選擇
public interface AbstractFactoryModel {
public Api create();
}
class Api1factory implements AbstractFactoryModel{
@Override
public Api create() {
Api api = new Api1();
return api;
}
}
3、單例模式:
懶漢和餓漢的區別有兩個:第一是懶漢是線程不安全的,餓漢是線程安全的;第二是懶漢實例化對象的時機是需要用到此對象的時候,餓漢實例化對象的時機是引用類本身的時候。
應用場景:對資源的佔有權很在意的情況,如I/O操作,數據庫操作,文件讀寫
public class SingleInstanceModel {
/*這裏賦空值,是懶漢模式和惡漢模式最大的卻別*/
/*懶漢模式是在使用到實例對象的時候纔會加載實例化對象,適用於數據量大的對象*/
public static SingleInstanceModel mLazyMan = null;
/*餓漢模式是在引用到類本身的時候就會加載實例化對象,適用於數據量小的對象*/
public static SingleInstanceModel mHungryMan = new SingleInstanceModel();
private SingleInstanceModel() {
};
/* 通過synchronized這個關鍵字可推,懶漢模式是一種線程不安全的模式 */
public static synchronized SingleInstanceModel newInstanceLazyMan() {
if (mLazyMan == null) {
mLazyMan = new SingleInstanceModel();
}
return mLazyMan;
}
/*線程安全*/
public static SingleInstanceModel newInstancehungryMan(){
return mHungryMan;
}
}
我們很多時候要即需要餓漢模式的效率,還要懶漢模式的延遲加載:
public class LazyAndHungryModelCombine {
private LazyAndHungryModelCombine() {
};
/*由於對於static關鍵字修飾的內容,當自身被引用的時候,就會加載進固定內存*/
private static class InstanceHolder {
private static LazyAndHungryModelCombine model = new LazyAndHungryModelCombine();
}
public static LazyAndHungryModelCombine newInstance() {
return InstanceHolder.model;
}
}
懶漢模式的雙重加鎖:
public class DoubleLockHungrMan {
/*
* volatile關鍵字修飾的變量不能在本地線程中緩存數據, 也就意味這每次都需要在進程的公
* 共內存區域去獲取數據, 這是對內存的直接操作
*/
private static volatile DoubleLockHungrMan hungrMan = null;
private DoubleLockHungrMan() {
}
public static DoubleLockHungrMan newInstance() {
if (hungrMan == null) {
synchronized (DoubleLockHungrMan.class) {
if (hungrMan == null) {
hungrMan = new DoubleLockHungrMan();
}
}
}
return hungrMan;
}
}
依賴反轉的例子:
通過類名,生成對象,平常的是通過類,生成對象
try {
DoubleLockHungrMan a=(DoubleLockHungrMan) Class.forName("DoubleLockHungrMan").newInstance();
} catch (InstantiationException | IllegalAccessException
| ClassNotFoundException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
這裏附上對Properties的操作:
很多時候,properties文件其實就是一個依賴容器,把一些映射放在這個文件中,如果要改變映射只需要改變這裏的內容即可
import java.io.IOException;
import java.io.InputStream;
import java.util.Properties;
public class PropertiesUsing {
private Properties mProperties = new Properties();
private InputStream mInput = null;
public PropertiesUsing() {
try {
mInput = PropertiesUsing.class.getResourceAsStream("PropertiesUsing.properties");
mProperties.load(mInput);
String str1 = mProperties.getProperty("str1");
String str2 = mProperties.getProperty("str2");
System.out.println(str1+str2);
} catch (IOException e) {
e.printStackTrace();
}
}
}
PropertiesUsing.properties的內容(這個文件放在src同在包下即可):
str1=hello
str2=world
3、建造者模式:
我覺得建造者模式,是將分工進行了細化;當一個產品是有很多的小部件組合,或者是一個產品需要很多設置的時候,並且不同的設置能產生不同效果的時候,就需要用到建造者模式
建造者分爲三部分的工作。
<pre name="code" class="java">import java.util.ArrayList;
public class BuilderModel {
public BuilderModel() {
CarBuilder builder = new CarBuilder();
Director director = new Director(builder);
ArrayList<String> sequence = new ArrayList<>();
sequence.add("part2");
sequence.add("part1");
sequence.add("part4");
sequence.add("part3");
director.setSequence(sequence);
director.construct();
builder.getProduct();
}
}
class Director {
private ArrayList<String> sequence = new ArrayList<>();
private Builder builder;
public Director(CarBuilder builder) {
this.builder = builder;
}
public void construct() {
if (sequence == null) {
System.out.println("sequence is null");
return;
}
for (String str : sequence) {
if ("part1".equals(str)) {
builder.makePart1();
} else if ("part2".equals(str)) {
builder.makePart2();
} else if ("part3".equals(str)) {
builder.makePart3();
} else if ("part4".equals(str)) {
builder.makePart4();
}
}
}
public void setSequence(ArrayList<String> sequence) {
this.sequence = sequence;
}
public ArrayList<String> getSequence() {
return sequence;
}
}
interface Builder {
public void makePart1();
public void makePart2();
public void makePart3();
public void makePart4();
public Car getProduct();
}
class CarBuilder implements Builder {
private Car car = new Car();
@Override
public void makePart1() {
car.setPart1("make part1");
}
@Override
public void makePart2() {
car.setPart2("make part2");
}
@Override
public void makePart3() {
car.setPart3("make part3");
}
@Override
public void makePart4() {
car.setPart4("make part4");
}
@Override
public Car getProduct() {
System.out.println(car.toString());
return car;
}
}
class Car {
private String part1;
private String part2;
private String part3;
private String part4;
public String getPart1() {
return part1;
}
public void setPart1(String part1) {
this.part1 = part1;
}
public String getPart2() {
return part2;
}
public void setPart2(String part2) {
this.part2 = part2;
}
public String getPart3() {
return part3;
}
public void setPart3(String part3) {
this.part3 = part3;
}
public String getPart4() {
return part4;
}
public void setPart4(String part4) {
this.part4 = part4;
}
public String toString() {
return "part1=" + part1 + ",part2=" + part2 + ",part3=" + part3
+ ",part4=" + part4;
}
}
4、原型模式:
淺拷貝:在clone的過程中,僅僅是將引用拷貝了一份,而每個引用指向的內容其實還是跟原來的變量指向的引用一致
深拷貝:與上述過程相反,在clone的過程中,將引用指向的對象一起克隆,在內存中重新開闢一個空間,來存放結構相同的數據結構
待續、、、、、、、、