Java設計模式快速入門
一、設計模式分類
- 大體上分為三大類:
- 建立型模式(5種):工廠方法模式,抽象工廠模式,單例模式,建造者模式,原型模式。
- 結構型模式(7種):介面卡模式,裝飾器模式,代理模式,外觀模式,橋接模式,組合模式,享元模式。
- 行為型模式(11種):策略模式、模板方法模式、觀察者模式、迭代子模式、責任鏈模式、命令模式、備忘錄模式、狀態模式、訪問者模式、中介者模式、直譯器模式。
二、設計模式原則
1. 開閉原則(Open Close Principle) 對擴充套件開放,對修改關閉。 2. 里氏代換原則(Liskov Substitution Principle) 只有當衍生類可以替換掉基類,軟體單位的功能不受到影響時,基類才能真正被複用,而衍生類也能夠在基類的基礎上增加新的行為。 3. 依賴倒轉原則(Dependence Inversion Principle) 這個是開閉原則的基礎,對介面程式設計,依賴於抽象而不依賴於具體。 4. 介面隔離原則(Interface Segregation Principle)使用多個隔離的藉口來降低耦合度。 5. 迪米特法則(最少知道原則)(Demeter Principle) 一個實體應當儘量少的與其他實體之間發生相互作用,使得系統功能模組相對獨立。 6. 合成複用原則(Composite Reuse Principle)原則是儘量使用合成/聚合的方式,而不是使用繼承。繼承實際上破壞了類的封裝性,超類的方法可能會被子類修改。
三、常見設計模式詳解
1. 工廠模式(Factory Method)
常用的工廠模式是靜態工廠,利用static方法,作為一種類似於常見的工具類Utils等輔助效果,一般情況下工廠類不需要例項化。
interface food{}
class A implements food{}
class B implements food{}
class C implements food{}
public class StaticFactory {
private StaticFactory(){}
public static food getA(){ return new A(); }
public static food getB(){ return new B(); }
public static food getC(){ return new C(); }
}
class Client{
//客戶端程式碼只需要將相應的引數傳入即可得到物件
//使用者不需要了解工廠類內部的邏輯。
public void get(String name){
food x = null ;
if ( name.equals("A")) {
x = StaticFactory.getA();
}else if ( name.equals("B")){
x = StaticFactory.getB();
}else {
x = StaticFactory.getC();
}
}
}
2. 抽象工廠模式(Abstract Factory)
一個基礎介面定義了功能,每個實現介面的子類就是產品,然後定義一個工廠介面,實現了工廠介面的就是工廠,這時候,介面程式設計的優點就出現了,我們可以新增產品類(只需要實現產品介面),只需要同時新增一個工廠類,客戶端就可以輕鬆呼叫新產品的程式碼。
抽象工廠的靈活性就體現在這裡,無需改動原有的程式碼,畢竟對於客戶端來說,靜態工廠模式在不改動StaticFactory類的程式碼時無法新增產品,如果採用了抽象工廠模式,就可以輕鬆的新增拓展類。
interface food{}
class A implements food{}
class B implements food{}
interface produce{ food get();}
class FactoryForA implements produce{
@Override
public food get() {
return new A();
}
}
class FactoryForB implements produce{
@Override
public food get() {
return new B();
}
}
public class AbstractFactory {
public void ClientCode(String name){
food x= new FactoryForA().get();
x = new FactoryForB().get();
}
}
3. 單例模式(Singleton)
在內部建立一個例項,構造器全部設定為private,所有方法均在該例項上改動,在建立上要注意類的例項化只能執行一次,可以採用許多種方法來實現,如Synchronized關鍵字,或者利用內部類等機制來實現。
public class Singleton {
private Singleton(){}
private static class SingletonBuild{
private static Singleton value = new Singleton();
}
public Singleton getInstance(){ return SingletonBuild.value ;}
}
4. 建造者模式(Builder)
在瞭解之前,先假設有一個問題,我們需要建立一個學生物件,屬性有name,number,class,sex,age,school等屬性,如果每一個屬性都可以為空,也就是說我們可以只用一個name,也可以用一個school,name,或者一個class,number,或者其他任意的賦值來建立一個學生物件,這時該怎麼構造?
難道我們寫6個1個輸入的建構函式,15個2個輸入的建構函式…….嗎?這個時候就需要用到Builder模式了。
public class Builder {
static class Student{
String name = null ;
int number = -1 ;
String sex = null ;
int age = -1 ;
String school = null ;
//構建器,利用構建器作為引數來構建Student物件
static class StudentBuilder{
String name = null ;
int number = -1 ;
String sex = null ;
int age = -1 ;
String school = null ;
public StudentBuilder setName(String name) {
this.name = name;
return this ;
}
public StudentBuilder setNumber(int number) {
this.number = number;
return this ;
}
public StudentBuilder setSex(String sex) {
this.sex = sex;
return this ;
}
public StudentBuilder setAge(int age) {
this.age = age;
return this ;
}
public StudentBuilder setSchool(String school) {
this.school = school;
return this ;
}
public Student build() {
return new Student(this);
}
}
public Student(StudentBuilder builder){
this.age = builder.age;
this.name = builder.name;
this.number = builder.number;
this.school = builder.school ;
this.sex = builder.sex ;
}
}
public static void main( String[] args ){
Student a = new Student.StudentBuilder().setAge(13).setName("LiHua").build();
Student b = new Student.StudentBuilder().setSchool("sc").setSex("Male").setName("ZhangSan").build();
}
}
5. 原型模式(Protype)
原型模式就是講一個物件作為原型,使用clone()方法來建立新的例項。
public class Prototype implements Cloneable{
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
protected Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
}finally {
return null;
}
}
public static void main ( String[] args){
Prototype pro = new Prototype();
Prototype pro1 = (Prototype)pro.clone();
}
}
//此處使用的是淺拷貝,關於深淺拷貝,大家可以另行查詢相關資料。
6. 介面卡模式(Adapter)
介面卡模式的作用就是在原來的類上提供新功能。主要可分為3種:
類適配:建立新類,繼承源類,並實現新介面,例如
class adapter extends oldClass implements newFunc{}物件適配:建立新類持源類的例項,並實現新介面,例如
class adapter implements newFunc { private oldClass oldInstance ;}介面適配:建立新的抽象類實現舊介面方法。例如
abstract class adapter implements oldClassFunc { void newFunc();}7. 裝飾模式(Decorator)
給一類物件增加新的功能,裝飾方法與具體的內部邏輯無關。
interface Source{ void method();}
public class Decorator implements Source{
private Source source ;
public void decotate1(){
System.out.println("decorate");
}
@Override
public void method() {
decotate1();
source.method();
}
}
8. 代理模式(Proxy)
客戶端通過代理類訪問,代理類實現具體的實現細節,客戶只需要使用代理類即可實現操作。
這種模式可以對舊功能進行代理,用一個代理類呼叫原有的方法,且對產生的結果進行控制。
interface Source{ void method();}
class OldClass implements Source{
@Override
public void method() {
}
}
class Proxy implements Source{
private Source source = new OldClass();
void doSomething(){}
@Override
public void method() {
new Class1().Func1();
source.method();
new Class2().Func2();
doSomething();
}
}
9. 外觀模式(Facade)
為子系統中的一組介面提供一個一致的介面,定義一個高層介面,這個介面使得這一子系統更加容易使用。這句話是百度百科的解釋,有點難懂,但是沒事,看下面的例子,我們在啟動停止所有子系統的時候,為它們設計一個外觀類,這樣就可以實現統一的介面,這樣即使有新增的子系統subSystem4,也可以在不修改客戶端程式碼的情況下輕鬆完成。
public class Facade {
private subSystem1 subSystem1 = new subSystem1();
private subSystem2 subSystem2 = new subSystem2();
private subSystem3 subSystem3 = new subSystem3();
public void startSystem(){
subSystem1.start();
subSystem2.start();
subSystem3.start();
}
public void stopSystem(){
subSystem1.stop();
subSystem2.stop();
subSystem3.stop();
}
}
10. 橋接模式(Bridge)
這裡引用下http://www.runoob.com/design-pattern/bridge-pattern.html的例子。Circle類將DrwaApi與Shape類進行了橋接.
interface DrawAPI {
public void drawCircle(int radius, int x, int y);
}
class RedCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: red, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
class GreenCircle implements DrawAPI {
@Override
public void drawCircle(int radius, int x, int y) {
System.out.println("Drawing Circle[ color: green, radius: "
+ radius +", x: " +x+", "+ y +"]");
}
}
abstract class Shape {
protected DrawAPI drawAPI;
protected Shape(DrawAPI drawAPI){
this.drawAPI = drawAPI;
}
public abstract void draw();
}
class Circle extends Shape {
private int x, y, radius;
public Circle(int x, int y, int radius, DrawAPI drawAPI) {
super(drawAPI);
this.x = x;
this.y = y;
this.radius = radius;
}
public void draw() {
drawAPI.drawCircle(radius,x,y);
}
}
//客戶端使用程式碼
Shape redCircle = new Circle(100,100, 10, new RedCircle());
Shape greenCircle = new Circle(100,100, 10, new GreenCircle());
redCircle.draw();
greenCircle.draw();
11. 組合模式(Composite)
組合模式是為了表示那些層次結構,同時部分和整體也可能是一樣的結構,常見的如資料夾或者樹。
abstract class component{}
class File extends component{ String filename;}
class Folder extends component{
component[] files ; //既可以放檔案File類,也可以放資料夾Folder類。Folder類下又有子檔案或子資料夾。
String foldername ;
public Folder(component[] source){ files = source ;}
public void scan(){
for ( component f:files){
if ( f instanceof File){
System.out.println("File "+((File) f).filename);
}else if(f instanceof Folder){
Folder e = (Folder)f ;
System.out.println("Folder "+e.foldername);
e.scan();
}
}
}
}
12. 享元模式(Flyweight)
使用共享物件的方法,用來儘可能減少記憶體使用量以及分享資訊。通常使用工廠類輔助,例子中使用一個HashMap類進行輔助判斷,資料池中是否已經有了目標例項,如果有,則直接返回,不需要多次建立重複例項。
abstract class flywei{ }
public class Flyweight extends flywei{
Object obj ;
public Flyweight(Object obj){
this.obj = obj;
}
}
class FlyweightFactory{
private HashMap<Object,Flyweight> data;
public FlyweightFactory(){ data = new HashMap<>();}
public Flyweight getFlyweight(Object object){
if ( data.containsKey(object)){
return data.get(object);
}else {
Flyweight flyweight = new Flyweight(object);
data.put(object,flyweight);
return flyweight;
}
}
}