设计模式剖析系列之原型模式

用一个已经创建的实例作为原型,克隆(clone)该原型对象来创建一个和原型相同或相似的新对象,免去创建对象的复杂过程和细节。原型模式分浅拷贝与深拷贝两种。
浅拷贝实现方式:
1.原型类实现CLoneable接口
2.拷贝对象通过原型的clone方法获得新的实例
深拷贝实现方式:
1.原型类实现CLoneable接口
2.原型类重写clone方法,并在克隆对象同时也克隆响应的引用类型成员变量。
————————————–
以下通过国宝熊猫的克隆来理解浅拷贝与深拷贝:
熊猫类包含两个成员属性:熊猫名字与饲养员。熊猫名字为普通字符串对象,饲养员为引用对象。以下分别通过浅拷贝和深拷贝两种方式克隆熊猫对象:
浅拷贝方式:
package net.mosang.prototype;
import java.util.Date;
/**
*
* @author heiry
*
*/
public class Panda implements Cloneable {
private String name;
private Feeder feeder;
//重写clone方法
@Override
protected Object clone() throws CloneNotSupportedException {
Panda panda = (Panda) super.clone();
return panda;
}
//setter、getter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Feeder getFeeder() {
return feeder;
}
public void setFeeder(Feeder feeder) {
this.feeder = feeder;
}
//构造方法
public Panda(String name, Feeder feeder) {
super();
this.name = name;
this.feeder = feeder;
}
}
package net.mosang.prototype;
public class Feeder {
public String name;
public void feed() {
System.out.println("feed panda....");
}
public Feeder(String name) {
super();
this.name = name;
}
}
package net.mosang.prototype;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Feeder feeder = new Feed犀利士
er("张大胖");
Panda p1 = new Panda("pangpang",feeder);
Panda p2 = (Panda) p1.clone();
System.out.println(p1);
System.out.println(p2);
feeder.name = "张小胖";
System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
}
}
运行结果:
net.mosang.prototype.Panda@15db9742
net.mosang.prototype.Panda@6d06d69c
p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖
p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张小胖
可见浅拷贝方式,虽然获得了一个与原型对象一样的新对象,但是对于引用类型成员变量feeder,拷贝的是地址而不是对象本身,换句话说,两个对象的feeder指向的是同一个Feeder对象。
深拷贝方式:
重点在于重写原型类的clone方法:
package net.mosang.prototype;
/**
*
* @author heiry
*
*/
public class Panda implements Cloneable{
private String name;
private Feeder feeder;
//重写clone方法,并将引用成员变量feeder同时克隆
@Override
protected Object clone() throws CloneNotSupportedException {
Object obj = super.clone();
Panda panda = (Panda) obj ;
panda.feeder = (Feeder)this.feeder.clone();
return panda;
}
//setter、getter
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Feeder getFeeder() {
return feeder;
}
public void setFeeder(Feeder feeder) {
this.feeder = feeder;
}
//构造方法
public Panda(String name, Feeder feeder) {
super();
this.name = name;
this.feeder = feeder;
}
}
package net.mosang.prototype;
public class Feeder implements Cloneable{
public String name;
public void feed() {
System.out.println("feed panda....");
}
public Feeder(String name) {
super();
this.name = name;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
package net.mosang.prototype;
public class Client {
public static void main(String[] args) throws CloneNotSupportedException {
Feeder feeder = new Feeder("张大胖");
Panda p1 = new Panda("pangpang",feeder);
Panda p2 = (Panda) p1.clone();
System.out.println(p1);
System.out.println(p2);
feeder.name = "张小胖";
System.out.println("p1----->"+p1+"p1饲养员:----->"+p1.getFeeder().name);
System.out.println("p2----->"+p2+"p2饲养员:----->"+p2.getFeeder().name);
}
}
运行结果:
net.mosang.prototype.Panda@15db9742
net.mosang.prototype.Panda@6d06d69c
p1----->net.mosang.prototype.Panda@15db9742p1饲养员:----->张小胖
p2----->net.mosang.prototype.Panda@6d06d69cp2饲养员:----->张大胖
可以看到,深拷贝的引用类型成员变量也是各自独立的。
设计模式剖析系列之建造者模式

建造者(Builder)模式的主要模块如下:
1. 建造者接口:负责建造各个组件
2.装配者接口:负责将组件组装成产品
3.产品类:成员变量为各组件对象
4.各个组件类
5. 建造者实现类:实现建造者接口
6.装配者实现类:实现装配者接口
7.客户端调用类
这里以建造超级计算机为例,演示构建者模式原理:
假设计算机由CPU/主板/内存三个部件组成,现在要生产一台陌桑超级计算机,CPU为AMD的CPU,主板为华硕主板,内存为256G容量内存。类关系图如下:

使用建造者模式具体做法:
package net.mosang.builder;
/**
* 具体产品类
* @author heiry
*
*/
public class Computer {
private CPU cpu;
private Mainboard mainboard;
private Memory memory;
public CPU getCpu() {
return cpu;
}
public void setCpu(CPU cpu) {
this.cpu = cpu;
}
public Mainboard getMainboard() {
return mainboard;
}
public void setMainboard(Mainboard mainboard) {
this.mainboard = mainboard;
}
public Memory getMemory() {
return memory;
}
public void setMemory(Memory memory) {
this.memory = memory;
}
}
package net.mosang.builder;
/**
* 构建子组件接口
* @author heiry
*
*/
public interface ComputerBuilder {
public CPU buildCPU();
public Mainboard buildMainboard();
public Memory buildMemory();
}
package net.mosang.builder;
/**
* 装配者接口
* @author heiry
*
*/
public interface ComputerDirector {
public abstract Computer directComputer();
}
package net.mosang.builder;
/**
* 构建者实现类
* 构建陌桑超级计算机部件
* @author wuah
*
*/
public class MosangSuperComputer implements ComputerBuilder {
@Override
public CPU buildCPU() {
System.out.println("陌桑超算使用的是AMD的CPU");
return new CPU("AMD");
}
@Override
public Mainboard buildMainboard() {
System.out.println("陌桑超算使用的是华硕主板");
return new Mainboard("华硕");
}
@Override
public Memory buildMemory() {
System.out.println("陌桑超算使用的是256G内存");
return new Memory(256);
}
}
package net.mosang.builder;
/**
* 装配者实现类:返回具体产品实例
* 陌桑超算由富士康代工装配
* @author heiry
*
*/
public class FoxconnDirector implements ComputerDirector {
private ComputerBuilder builder;
@Override
public Computer directComputer() {
CPU cpu = builder.buildCPU();
Mainboard mainboard = builder.buildMainboard();
Memory memory = builder.buildMemory();
Computer c = new Computer();
c.setCpu(cpu);
c.setMainboard(mainboard);
c.setMemory(memory);
return c;
}
public FoxconnDirector(ComputerBuilder builder) {
super();
this.builder = builder;
}
}
package net.mosang.builder;
/**
* 具体部件类:CPU
* @author heiry
*
*/
public class CPU {
private String brands;
public String getBrands() {
return brands;
}
public void setBrands(String brands) {
this.brands = brands;
}
public CPU(String brands) {
super();
this.brands = brands;
}
}
package net.mosang.builder;
/**
* 具体部件类:内存
* @author heiry
*
*/
public class Memory {
private int capacity;
public Memory(int capacity) {
super();
this.capacity = capacity;
}
public int getCapacity() {
return capacity;
}
public void setCapacity(int capacity) {
this.capacity = capacity;
}
}
package net.mosang.builder;
/**
* 具体部件类:主板
* @author heiry
*
*/
public class Mainboard {
private String producer;
public String getProducer() {
return producer;
}
public void setProducer(String producer) {
this.producer = producer;
}
public Mainboard(String producer) {
super();
this.producer = producer;
}
}
package net.mosang.builder;
/**
* 客户端调用类
* @author heiry
*
*/
public class Client {
public static void main(String[] args) {
MosangSuperComputer msc = new MosangSuperComputer();
FoxconnDirector fd = new FoxconnDirector(msc);
Computer myComputer = fd.directComputer();
System.out.println(myComputer);
}
}
输出结果
陌桑超算使用的是AMD的CPU
陌桑超算使用的是华硕主板
陌桑超算使用的是256G内存
net.mosang.builder.Computer@15db9742
设计模式剖析系列之单例模式

核心点:
—— 单例类只有一个实例对象;
—— 该单例对象必须由单例类自行创建;
—— 单例类对外提供一个访问该单例的全局访问点;
实现方式:
1.构造方法私有
2.提供类自身定义一个静态私有实例
3.向外提供一个静态的公有方法用于创建或获取该静态私有实例,该方法是对外唯一提供的创建实例途径。
主要分类:
——饿汉式:类一旦加载就创建实例,保证在调用静态方法之前单例已经存在了,特点是线程安全。
——懒汉式:只有在第一次调用的时候才会创建,非线程安全,需要考虑线程同步。
package net.mosang.singleton;
/**
* 饿汉式单例模式
* @author heiry
*
*/
public class HungrySingLeton {
private static HungrySingLeton instance = new HungrySingLeton();
private HungrySingLeton() {//私有构造方法
}
public static HungrySingLeton getInstance() { //对外提供唯一的获取实例方法
return instance;
}
}
package net.mosang.singleton;
/**
* 懒汉式单例模式
* @author heiry
*
*/
public class LazySingLeton {
private static LazySingLeton instance =null;
private LazySingLeton() {//私有构造方法
}
public static synchronized LazySingLeton getInstance() { //synchronized线程同步,避免并发创建多个对象
if(instance==null) {
instance = new LazySingLeton();
}
return instance;
}
}
设计模式剖析系列之工厂方法模式

静态工厂方法只有一个工厂类,且如果要增加产品,则需要修改工厂类代码,违背了开闭原则。工厂方法模式则将工厂类颗粒化,为每一种产品单独设立一个工厂类。

package staticfactory;
public interface Computer {
public abstract void cal();
}
package net.mosang.factory;
public class Mac implements Computer {
@Override
public void cal() {
System.out.println("苹果电脑启动。。。。");
}
}
package net.mosang.factory;
public class HP implements Computer {
@Override
public void cal() {
System.out.println("惠普电脑启动。。。。");
}
}
package net.mosang.factory;
public interface ComputerFactoryBasic {
public abstract Computer CreateComputer();
}
package net.mosang.factory;
public class MacFactory implements ComputerFactoryBasic {
@Override
public Computer CreateComputer() {
return new Mac();
}
}
package net.mosang.factory;
public class HPFactory implements ComputerFactoryBasic {
@Override
public Computer CreateComputer() {
return new HP();
}
}
package net.mosang.factory;
public class Client {
public static void main(String[] args) {
Computer computer = new MacFactory().CreateComputer();
Computer computer2 = new HPFactory().CreateComputer();
computer.cal();
computer2.cal();
}
}
输出结果
苹果电脑启动。。。。
惠普电脑启动。。。。
设计模式剖析系列之静态工厂方法

作用:在Think in java 系列书籍以及网上大量的文章都写了其各种各样的好处,我认为言过其实,我们用静态工厂方法,主要原因在于可以根据逻辑需求返回实例对象。可以方便实现工厂模式、单例模式。其它如,有语义方法名、返回其返回类型的任何子类型的对象,方便创建参数化类型实例等等都是无关痛痒的东西。
实现:
将创建实例封装在一个工厂类的静态方法中,静态方法不同的参数返回不同的实例。
示例:
如下所示,电脑工厂类,通过提供静态方法getComputer(String Brand)生产不同品牌的电脑(返回Computer实例对象),客户端只需要调用静态工厂方法传入不同参数即可获得目标对象。

package staticfactory;
public interface Computer {
public abstract void cal();
}
package staticfactory;
public class Mac implements Computer {
@Overrid
public void cal() {
System.out.println("苹果电脑启动。。。。");
}
}
package staticfactory;
public class HP implements Computer {
@Override
public void cal() {
System.out.println("惠普电脑启动。。。。");
}
}
package staticfactory;
public class ComputerFactory {
public static Computer getComputer(String computerBrand) {
switch (computerBrand) {
case "Mac":
return new Mac();
case "HP":
return new HP();
default:
return null;
}
}
}
package staticfactory;
public class Client {
public static void main(String[] args) {
Computer computer = ComputerFactory.getComputer("Mac");
Computer computer2 = ComputerFactory.getComputer("HP");
computer.cal();
computer2.cal();
}
}
运行结果:
苹果电脑启动。。。。
惠普电脑启动。。。。
设计模式剖析系列之面向对象设计原则
一.开闭原则

实现方式:
1. 遵循“抽象约束、封装变化”原则,通过接口或者抽象类为实体定义一个相对稳定的抽象层,而将相同的可变因素封装在相同的具体实现类中。
2.参数类型、引用对象尽量使用接口或者抽象类,而不是实现类。
3.缩小功能颗粒度。功能粒度越小,被复用的可能性就越大,重复利用可能性就越高。
二. 里氏替换原则

简单地说,把父类都替换成它的子类,程序的行为没有变化。只要出现父类的地方,均可用子类替换,而且对整体实现并没有任何影响,提高代码的复用性。
实现方式:
子类继承父类时,除添加新的方法完成新增功能外,尽量不要重写父类的方法。
三. 依赖倒置原则

——高层模块不应该依赖低层模块,两者都应该依赖其抽象
——抽象不应该依赖细节
——细节应该依赖抽象
实现方式:
1.每个类尽量提供接口或抽象类,或者两者都具备。
2.变量的声明类型尽量是接口或者是抽象,模块间的依赖通过抽象发生,实现类之间不发生直接的依赖关系,其依赖关系是通过接口或抽象类产生的。
3.任何类都不应该从具体类派生。
4.尽量不要重写基类已经写好的方法(符合里氏替换原则)。