public class SimpleFactory {
public static void main(String[] args) throws IllegalAccessException, InstantiationException {
//实例化一个Apple,用到了工厂类
Fruit apple = FruitFactory.getFruit("apple");
//实例化一个Banana,用到了工厂类
Fruit banana= FruitFactory.getFruit("banana");
apple.get();
banana.get();
}
}
interface Fruit {
public void get();
}
class Apple implements Fruit{
public void get(){
System.out.println("采集苹果");
}
}
class Banana implements Fruit{
public void get(){
System.out.println("采集香蕉");
}
}
class FruitFactory {
public static Fruit getFruit(String type) throws InstantiationException, IllegalAccessException{
//不区分大小写
if(type.equalsIgnoreCase("Apple")){
return Apple.class.newInstance();
}else if(type.equalsIgnoreCase("Banana")){
return Banana.class.newInstance();
}else{
System.out.println("找不到相应的实体类");
return null;
}
}
}
/**
简单工厂模式中包含的角色及其职责
1、工厂(Creater)角色
简单工厂模式的核心,它负责实现创建所有实例的内部逻辑。工厂类可以被外界直接调用,创建所需的产品对象。(FruitFactory类)
2、抽象(Product)角色
简单工厂模式所创建的所有对象的父类,它负责描述所有实例所共有的公共接口。(Fruit接口)
3、具体产品(Concrete Product)角色
简单工厂模式所创建的具体实例对象。(Apple类与Banana类)
简单设计模式的优缺点:
优点:简单工厂模式中,工厂类是整个模式的关键所在。它包含必要的判断逻辑,能够根据外界给定的信息,决定究竟应该创建哪个具体类的对象。用户在创建时可以直接使用工厂类去创建所需的实例,而无需去了解这些对象是如何创建以及如何组织的,明确区分了各自的职责和权力,有利于整个软件体系结构的优化。
缺点:很明显简单工厂模式的缺点也体现在其工厂类上,由于工厂类集中了所有实例的创建逻辑,容易违反GRASPR的高内聚的责任分配原则,另外,当系统中的具体产品类不断增多时,可能会出现要求更改相应工厂类的情况,拓展性并不是很好。
使用场景
1、工厂类负责创建的对象比较少;
2、客户只知道传入工厂类的参数,对于如何创建对象(逻辑)不关心;
3、由于简单工厂很容易违反高内聚责任分配原则,因此一般只在很简单的情况下应用。
*/
public class FactoryMethod {
public static void main(String[] args) {
//获得AppleFactory
FruitFactory af = new AppleFactory();
//通过AppleFactory来获得Apple实例对象
Fruit apple = af.getFruit();
apple.get();
//获得BananaFactory
FruitFactory bf = new BananaFactory();
//通过BananaFactory来获得Apple实例对象
Fruit banana = bf.getFruit();
banana.get();
}
}
interface Fruit {
public void get();
}
class Apple implements Fruit{
public void get(){
System.out.println("采集苹果");
}
}
class Banana implements Fruit{
public void get(){
System.out.println("采集香蕉");
}
}
class Pear implements Fruit{ //具体产品
public void get() {
System.out.println("采集梨子");
}
}
//创建一个抽象工厂
interface FruitFactory {
public Fruit getFruit();
}
//分別针对不同的具体实例创建不同的工厂实现方法,符号开闭原则
class AppleFactory implements FruitFactory {
public Fruit getFruit() {
return new Apple();
}
}
class BananaFactory implements FruitFactory {
public Fruit getFruit() {
return new Banana();
}
}
/**
*工厂方法模式中包含的角色及其职责
* 1、抽象工厂(Creator)角色:(FruitFactory)
* 是工厂方法模式的核心,与应用程序无关。任何在模式中创建的对象的工厂类必须实现这个接口。
* 2、具体工厂(Concrete Creator)角色:(AppleFactory、BananaFactory)
* 这是实现抽象工厂接口的具体工厂类,包含与应用程序密切相关的逻辑,并且受到应用程序调用以创建产品对象。在上图中有两个这样的角色:BulbCreator与TubeCreator。
* 3、抽象产品(Product)角色:(Fruit)
* 工厂方法模式所创建的对象的超类型,也就是产品对象的共同父类或共同拥有的接口。在上图中,这个角色是Light。
* 4、具体产品(Concrete Product)角色:(Apple、Banana)
* 这个角色实现了抽象产品角色所定义的接口。某具体产品有专门的具体工厂创建,它们之间往往一一对应。
*
* 工厂方法模式与简单工厂模式比较
* 1、工厂方法模式与简单工厂模式在结构上的不同不是很明显。工厂方法类的核心是一个抽象工厂类,而简单工厂模式把核心放在一个具体类上。
*
* 2、工厂方法模式之所以有一个别名叫多态性工厂模式是因为具体工厂类都有共同的接口,或者有共同的抽象父类。
*
* 3、当系统扩展需要添加新的产品对象时,仅仅需要添加一个具体对象以及一个具体工厂对象,原有工厂对象不需要进行任何修改,也不需要修改客户端,很好的符合了开放-封闭原则。而简单工厂模式在添加新产品对象后,不得不修改工厂方法,扩展性不好。
*
* 4、工厂方法模式退化后可以演变成简单工厂模式。
*
* 应用场景
* 工厂方法经常用在以下两种情况中:
* 第一种情况是对于某个产品,调用者清楚地知道应该使用哪个具体工厂服务,实例化该具体工厂,生产出具体的产品来。Java Collection中的iterator() 方法即属于这种情况。
* 第二种情况,只是需要一种产品,而不想知道也不需要知道究竟是哪个工厂为生产的,即最终选用哪个具体工厂的决定权在生产者一方,它们根据当前系统的情况来实例化一个具体的工厂返回给使用者,而这个决策过程这对于使用者来说是透明的。
*
*/
public class Danli {
}
//饿汉式
class Person2 {
public static final Person2 person2 = new Person2();
//构造函数私有化
private Person2(){}
//提供一个全局的静态方法
public static Person2 getPerson(){
return person2;
}
}
//懒汉式,效率高,但线程不安全
class Person3 {
public static Person3 person3 = null;
//构造函数私有化
private Person3(){}
//提供一个全局的静态方法
public static Person3 getPerson(){
if(person3 == null){
person3 = new Person3();
}
return person3;
}
}
//懒汉式,效率低,但线程安全
class Person4 {
public static Person4 person = null;
//构造函数私有化
private Person4(){}
//提供一个全局的静态方法
public static synchronized Person4 getPerson(){
if(person == null){
person = new Person4();
}
return person;
}
}
//双重检查(对懒汉式的升级,效率更高)(重)
class Person {
public static Person person = null;
//构造函数私有化
private Person(){}
//提供一个全局的静态方法
public static Person getPerson(){
if(person == null){
synchronized(Person.class){
if(person == null){
person = new Person();
}
}
}
return person;
}
}
public class MyTest {
public static void main(String[] args) {
Car car = new RunCar();
Car swimCar = new SwimCarDecorator(car);
Car flycar = new FlyCarDecorator(swimCar);
flycar.show();
}
}
interface Car {
public void run();
public void show();
}
class RunCar implements Car {
public void run() {
System.out.println("可以跑");
}
public void show() {
this.run();
}
}
abstract class CarDecorator implements Car {
private Car car;
public CarDecorator(Car car) {
this.car = car;
}
public Car getCar() {
return car;
}
public void setCar(Car car) {
this.car = car;
}
public abstract void show();
}
class SwimCarDecorator extends CarDecorator {
public SwimCarDecorator(Car car) {
super(car);
}
@Override
public void show() {
this.getCar().show();
this.swim();
this.run();
}
public void run() {
}
public void swim() {
System.out.println("可以游泳");
}
}
class FlyCarDecorator extends CarDecorator {
public FlyCarDecorator(Car car) {
super(car);
}
@Override
public void show() {
this.getCar().show();
this.fly();
}
public void fly() {
System.out.println("可以飞");
}
public void run() {
}
}
/**
装饰模式的角色与职责:
1、抽象组件角色(Component): 一个抽象接口,是被装饰类和装饰类的父接口。(Car)
2、具体组件角色(ConcreteComponent):为抽象组件的实现类。(RunCar)
3、抽象装饰角色(Decorator):包含一个组件的引用,并定义了与抽象组件一致的接口。(CarDecorator)
4、具体装饰角色(ConcreteDecorator):为抽象装饰角色的实现类。负责具体的装饰。(FlyCarDecorator、SwimCarDecorator)
使用范围
以下情况使用Decorator模式
1. 需要扩展一个类的功能,或给一个类添加附加职责。
2. 需要动态的给一个对象添加功能,这些功能可以再动态的撤销。
3. 需要增加由一些基本功能的排列组合而产生的非常大量的功能,从而使继承关系变的不现实。
4. 当不能采用生成子类的方法进行扩充时。一种情况是,可能有大量独立的扩展,为支持每一种组合将产生大量的子类,使得子类数目呈爆炸性增长。另一种情况可能是因为类定义被隐藏,或类定义不能用于生成子类。
装饰模式的优缺点
优点
1. Decorator模式与继承关系的目的都是要扩展对象的功能,但是Decorator可以提供比继承更多的灵活性。
2. 通过使用不同的具体装饰类以及这些装饰类的排列组合,设计师可以创造出很多不同行为的组合。
缺点
1. 这种比继承更加灵活机动的特性,也同时意味着更加多的复杂性。
2. 装饰模式会导致设计中出现许多小类,如果过度使用,会使程序变得很复杂。
3. 装饰模式是针对抽象组件(Component)类型编程。但是,如果你要针对具体组件编程时,就应该重新思考你的应用架构,以及装饰者是否合适。当然也可以改变Component接口,增加新的公开的行为,实现“半透明”的装饰者模式。在实际项目中要做出最佳选择。
*/
package cn.it.cast.Test;
import java.util.Observable;
import java.util.Observer;
/**
* Observer模式是行为模式之一,它的作用是当一个对象的状态发生变化时
* ,能够自动通知其他关联对象,自动刷新对象状态。
*
* Observer模式提供给关联对象一种同步通信的手段,
* 使某个对象与依赖它的其他对象之间保持状态同步。
*/
public class Obsever {
public static void main(String[] args) {
Person person = new Person();
//注册观察者
person.addObserver(new MyObserver());
person.addObserver(new MyObserver());
person.setName("小明");
person.setSex("男");
person.setAge(18);
//获得当前对象已注册的观察者数目
System.out.println(person.countObservers());
}
}
class Person extends Observable {
private String name;
private String sex;
private int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
this.setChanged();
this.notifyObservers();
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
this.setChanged();
this.notifyObservers();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
this.setChanged();
this.notifyObservers();
}
}
class MyObserver implements Observer {
public void update(Observable o, Object arg) {
System.out.println("对象已改变");
}
}
/**
* 观察者模式的典型应用
* 1、侦听事件驱动程序设计中的外部事件
*
* 2、侦听/监视某个对象的状态变化
*
* 3、发布者/订阅者(publisher/subscriber)模型中,当一个外部事件(新的产品,消息的出现等等)被触发时,
* 通知邮件列表中的订阅者
*/
package cn.it.cast;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
/**
* Proxy模式又叫做代理模式,是构造型的设计模式之一,
* 它可以为其他对象提供一种代理(Proxy)以控制对这个对象的访问。
*
* 所谓代理,是指具有与代理元(被代理的对象)
* 具有相同的接口的类,客户端必须通过代理与被代理的目标类交互,
* 而代理一般在交互的过程中(交互前后),进行某些特别的处理。
*
* 动态代理有以下特点:
*
* 1.代理对象,不需要实现接口
*
* 2.代理对象的生成,是利用JDK的API,
* 动态的在内存中构建代理对象(需要我们指定创建代理对象/
* 目标对象实现的接口的类型)
*
* 3.动态代理也叫做:JDK代理,接口代理
*
* 代理代理,Subject与RealSubject不变
*
* 而使用动态代理,首先要创建代理实例的调用处理程序,
* 通过这个程序来执行代理对象特有的方法
*/
//静态代理比较简单,先看动态代理
public class Daili {
public static void main(String[] args) {
Subject2 realSubject2 = new RealSubject2();
MyHandler myHandler = new MyHandler(realSubject2);
// 返回一个指定接口的代理类实例,该接口可以将方法调用指派到指定的调用处理程序
//只能用接口类型,证明了proxy代理只能代理接口
Subject2 proxySubject = (Subject2)Proxy.newProxyInstance(RealSubject2.class.getClassLoader(),RealSubject2.class.getInterfaces(), myHandler);
proxySubject.sailBook();
}
}
interface Subject {
public void sailBook();
}
interface Subject2 {
public void sailBook();
}
class RealSubject implements Subject {
@Override
public void sailBook() {
System.out.println("卖书");
}
}
class RealSubject2 implements Subject2 {
@Override
public void sailBook() {
System.out.println("卖书2");
}
}
class MyHandler implements InvocationHandler{
private Object subject;
public MyHandler(Object subject){
this.subject=subject;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
this.dazhe();
Object result = method.invoke(subject,args);
give();
return result;
}
public void dazhe() {
System.out.println("打折");
}
public void give() {
System.out.println("赠送代金券");
}
}
package cn.it.cast.Test;
/**
* 适配器模式
* Adapter模式也叫适配器模式,是构造型模式之一,通过Adapter模式可以改变已有类(或外部类)的接口形式。
*
* 举个例子:我们使用电脑,家里的电源是220V的,
* 而我们的电脑是18V的,这时如果我们直接把电源连接电脑,
* 一定会导致电脑被烧坏,因为电源电压太高了,这时我们就需要一个电源适配器,
* 连接在电源与电脑之间,通过适配器进行一个降压,来保证电脑的正常工作。
*/
public class shipeiqi {
public static void main(String[] args) {
AdapterSupply2 adapterSupply2 = new AdapterSupply2(new PowerSupply());
adapterSupply2.AdaperSupply();
}
}
//先写个电源类
class PowerSupply{
public void powerSupply(){
System.out.println("使用220v电源");
}
}
//适配器类
class AdapterSupply extends PowerSupply{
public void AdaperSupply(){
super.powerSupply();
this.Supply18V();
}
public void Supply18V(){
System.out.println("将220v电压降为18v");
}
}
//适配器类.第二种模式,将被适配对象作为成员变量
//一般,使用第二种委让形式更多一些,因为这种方式不必继承,使用成员变量更加的灵活
class AdapterSupply2{
private PowerSupply powerSupply;
public AdapterSupply2(PowerSupply powerSupply){
this.powerSupply = powerSupply;
}
public void AdaperSupply(){
powerSupply.powerSupply();
this.Supply18V();
}
public void Supply18V(){
System.out.println("将220v电压降为18v");
}
}
package cn.it.cast.Test;
/**
* 概念:
* Template Method模式也叫模板方法模式,是行为模式之一,它把具有特定步骤算法中的某些必要的处理委让给抽象方法,通过子类继承对抽象方法的不同实现改变整个算法的行为。
*
* 模板方法模式的应用场景
* Template Method模式一般应用在具有以下条件的应用中:
*
* 1、具有统一的操作步骤或操作过程
*
* 2、具有不同的操作细节
*
* 3、存在多个具有同样操作步骤的应用场景,但某些具体的操作细节却各不相同
*
* 模板方法模式的应用实例
* 1、在造房子的时候,地基、走线、水管都一样,只有在建筑的后期才有加壁橱加栅栏等差异。
*
* 2、西游记里面菩萨定好的 81 难,这就是一个顶层的逻辑骨架。
*
* 3、spring 中对 Hibernate 的支持,将一些已经定好的方法封装起来,比如开启事务、获取 Session、关闭 Session 等,程序员不重复写那些已经规范好的代码,直接丢一个实体就可以保存。
*/
public class mubanfangfa {
public static void main(String[] args) {
Makecar makecar = new BusMaker();
makecar.Makecar();
}
}
abstract class Makecar{
public abstract void makeHead();
public abstract void makeBody();
public abstract void maketail();
public void Makecar(){
this.makeHead();
this.makeBody();
this.maketail();
}
}
class BusMaker extends Makecar{
@Override
public void makeHead() {
System.out.println("公交车头");
}
@Override
public void makeBody() {
System.out.println("公交车身");
}
@Override
public void maketail() {
System.out.println("公交车位");
}
}
import java.util.ArrayList;
import java.util.List;
public class yuanxing {
public static void main(String[] args) {
//浅克隆
Person5 person1 = new Person5();
Person5 person2 = person1.clone();
}
}
//如果要克隆就必须实现Cloneable接口
class Person5 implements Cloneable{
//可能会抛出不支持克隆异常,原因是没有实现Cloneable接口
@Override
protected Person5 clone(){
try{
return (Person5) super.clone();
}catch(CloneNotSupportedException e){
e.printStackTrace();
return null;
}
}
}
//如果要克隆就必须实现Cloneable接口
class Person implements Cloneable{
private String name;
private String sex;
private List list;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSex() {
return sex;
}
public void setSex(String sex) {
this.sex = sex;
}
public List getList() {
return list;
}
public void setList(List list) {
this.list = list;
}
//可能会抛出不支持克隆异常,原因是没有实现Cloneable接口
@Override
protected Person clone(){
try{
Person person = (Person) super.clone();
List newList = new ArrayList();
//将引用类型进行赋值
for(String str : this.list){
newList.add(str);
}
person.setList(newList);
return person;
}catch(CloneNotSupportedException e){
e.printStackTrace();
return null;
}
}
}
/**
注意:final 类型修饰的成员变量不能进行深度拷贝
最后说一下,原型模式的使用场景
1、在创建对象的时候,我们不只是希望被创建的对象继承其基类的基本结构,还希望继承原型对象的数据。
2、希望对目标对象的修改不影响既有的原型对象(深度克隆的时候可以完全互不影响)。
3、隐藏克隆操作的细节,很多时候,对对象本身的克隆需要涉及到类本身的数据细节。
4、类初始化需要消化非常多的资源,这个资源包括数据、硬件资源等;
5、通过 new 产生一个对象需要非常繁琐的数据准备或访问权限,则可以使用原型模式;
6、一个对象需要提供给其他对象访问,而且各个调用者可能都需要修改其值时,可以考虑使用原型模式拷贝多个对象供调用者使用。在实际项目中,原型模式很少单独出现,一般是和工厂方法模式一起出现,通过 clone的方法创建一个对象,然后由工厂方法提供给调用者。原型模式先产生出一个包含
大量共有信息的类,然后可以拷贝出副本,修正细节信息,建立了一个完整的个性对象。
/
package cn.it.cast.Test;
/**
* Builder模式也叫建造者模式或者生成器模式,是由GoF提出的23种设计模式中的一种。
* Builder模式是一种对象创建型模式之一,用来隐藏复合对象的创建过程,
* 它把复合对象的创建过程加以抽象,通过子类继承和重载的方式,动态地创建具有复合属性的对象。
*
*
* 适用范围
* 1、对象的创建:Builder模式是为对象的创建而设计的模式
*
* 2、创建的是一个复合对象:被创建的对象为一个具有复合属性的复合对象
*
* 3、关注对象创建的各部分的创建过程:不同的工厂(这里指builder生成器)对产品属性有不同的创建方法
*/
public class Constructer {
public static void main(String[] args) {
//施工队造房子
HouseBuilder loufangBuilder = new LoufangBuilder();
// loufangBuilder.makeFloor();
// loufangBuilder.makeWall();
// loufangBuilder.makeRoof();
//指挥者
HouseDirector houseDirector = new HouseDirector(loufangBuilder);
houseDirector.make();
House house = loufangBuilder.getHouse();
System.out.println(house.getFloor());
System.out.println(house.getWall());
System.out.println(house.getRoof());
}
}
//房子
class House {
//地板
private String floor;
//墙
private String wall;
//房顶
private String roof;
public String getFloor() {
return floor;
}
public void setFloor(String floor) {
this.floor = floor;
}
public String getWall() {
return wall;
}
public void setWall(String wall) {
this.wall = wall;
}
public String getRoof() {
return roof;
}
public void setRoof(String roof) {
this.roof = roof;
}
}
//声明一个施工队的接口
interface HouseBuilder {
//修地板
public void makeFloor();
//修墙
public void makeWall();
//修屋顶
public void makeRoof();
//获得修好的房子
public House getHouse();
}
//新建一个施工队,实现此接口
class LoufangBuilder implements HouseBuilder{
House house = new House();
public void makeFloor() {
house.setFloor("楼房->地板");
}
public void makeWall() {
house.setWall("楼房->墙");
}
public void makeRoof() {
house.setRoof("楼房->屋顶");
}
public House getHouse() {
return house;
}
}
//新建一个指挥者
class HouseDirector {
private HouseBuilder houseBuilder;
public HouseDirector(HouseBuilder houseBuilder){
this.houseBuilder = houseBuilder;
}
public void make(){
houseBuilder.makeFloor();
houseBuilder.makeWall();
houseBuilder.makeRoof();
}
}
package cn.it.cast.Test;
/**
* Strategy模式也叫策略模式是行为模式之一,它对一系列的算法加以封装,
* 为所有算法定义一个抽象的算法接口,并通过继承该抽象算法接口对所有的算法加以封装和实现,
* 具体的算法选择交由客户端决定(策略)。Strategy模式主要用来平滑地处理算法的切换 。
*
* 举个例子:假如有两个加密算法,我们分别调用他们,之前我们可以这么写
*/
public class Celue {
public static void main(String[] args) {
Context md5 = new Context(new MD5Strategy());
md5.encrypt();
Context rsa = new Context(new RSAStrategy());
rsa.encrypt();
}
}
interface Strategy {
//加密
public void encrypt();
}
class MD5Strategy implements Strategy {
public void encrypt() {
System.out.println("执行MD5加密");
}
}
class RSAStrategy implements Strategy {
public void encrypt() {
System.out.println("执行RSA加密");
}
}
//新建一个Context类,这个类是策略模式的核心类,
// 类似于一个工厂,它包含了所有算法类的所有方法
//为什么感觉和工厂模式没区别
class Context {
private Strategy strategy;
public Context(Strategy strategy) {
this.strategy = strategy;
}
public void encrypt() {
this.strategy.encrypt();
}
}
/**
* 策略模式的角色与职责
* 1、Strategy: 策略(算法)抽象。(Strategy接口)
*
* 2、ConcreteStrategy:各种策略(算法)的具体实现。(MD5Strategy、RSAStrategy)
*
* 3、Context:策略的外部封装类,或者说策略的容器类。根据不同策略执行不同的行为。策略由外部环境决定。(Context)
*
*
*
* 策略模式的优缺点:
* 优点:
* 1. 策略模式提供了管理相关的算法族的办法。策略类的等级结构定义了一个算法或行为族。恰当使用继承可以把公共的代码移到父类里面,从而避免重复的代码。
*
* 2. 策略模式提供了可以替换继承关系的办法。继承可以处理多种算法或行为。如果不是用策略模式,那么使用算法或行为的环境类就可能会有一些子类,每一个子类提供一个不同的算法或行为。但是,这样一来算法或行为的使用者就和算法或行为本身混在一起。决定使用哪一种算法或采取哪一种行为
*
* 的逻辑就和算法或行为的逻辑混合在一起,从而不可能再独立演化。继承使得动态改变算法或行为变得不可能。
*
* 3. 使用策略模式可以避免使用多重条件转移语句。多重转移语句不易维护,它把采取哪一种算法或采取哪一种行为的逻辑与算法或行为的逻辑混合在一起,统统列在一个多重转移语句里面,比使用继承的办法还要原始和落后。
*
* 缺点:
* 1.客户端必须知道所有的策略类,并自行决定使用哪一个策略类。这就意味着客户端必须理解这些算法的区别,以便适时选择恰当的算法类。换言之,策略模式只适用于客户端知道所有的算法或行为的情况。
*
* 2. 策略模式造成很多的策略类。有时候可以通过把依赖于环境的状态保存到客户端里面,而将策略类设计成可共享的,这样策略类实例可以被不同客户端使用。换言之,可以使用享元模式来减少对象的数量。
*
* 应用场景:
* 1、 多个类只区别在表现行为不同,可以使用Strategy模式,在运行时动态选择具体要执行的行为。
* 2、 需要在不同情况下使用不同的策略(算法),或者策略还可能在未来用其它方式来实现。
* 3、 对客户隐藏具体策略(算法)的实现细节,彼此完全独立
*/
package cn.it.cast.Test;
import java.util.HashMap;
import java.util.Map;
/**
* Flyweight模式也叫享元模式,是构造型模式之一,
* 它通过与其他类似对象共享数据来减小内存占用。它使用共享物件,
* 用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;
* 它适合用于只是因重复而导致使用无法令人接受的大量内存的大量物件。
* 通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,
* 当需要使用时再将它们传递给享元。
*
* 享元模式的角色和职责
* 1、抽象享元角色:为具体享元角色规定了必须实现的方法,而外蕴状态就是以参数的形式通过此方法传入。在Java中可以由抽象类、接口来担当。。
*
* 2、具体享元角色:实现抽象角色规定的方法。如果存在内蕴状态,就负责为内蕴状态提供存储空间。
*
* 3、享元工厂角色:负责创建和管理享元角色。要想达到共享的目的,这个角色的实现是关键。
*
* 4、客户端角色 :维护对所有享元对象的引用,而且还需要存储对应的外蕴状态。
*
* 两个状态
* 1、内蕴状态存储在享元内部,不会随环境的改变而有所不同,是可以共享的
* 2、外蕴状态是不可以共享的,它随环境的改变而改变的,因此外蕴状态是由客户端来保持(因为环境的变化是由客户端引起的)。
*/
public class Xiangyuan {
}
interface Flyweight{
public void display();
}
class MyFlyweight implements Flyweight{
private String str;
public MyFlyweight(String str){
this.str = str;
}
public void display(){
System.out.println(str);
}
}
class MyFlyweightFactory {
private Map pool;
public MyFlyweightFactory(){
pool = new HashMap();
}
//利用map
public Flyweight getMyFlyweight(String str){
MyFlyweight myFlyweight = pool.get(str);
//若池中没有则创建一个新的并放入池中,若池中已存在,则返回池中的
if(myFlyweight == null){
myFlyweight = new MyFlyweight(str);
pool.put(str, myFlyweight);
}
return myFlyweight;
}
}
/**
* Flyweight myFlyweight1 = new MyFlyweight("a");
* Flyweight myFlyweight2 = new MyFlyweight("b");
* Flyweight myFlyweight3 = new MyFlyweight("a");
* Flyweight myFlyweight4 = new MyFlyweight("d");
*
* 如果采用普通方法创建,虽然值相同,
* 但却不是同一个对象,说明虽然对象内部一模一样,
* 但却创建了两个对象,这样就浪费了资源。
*
* 使用场景
* 如果一个应用程序使用了大量的对象,而这些对象造成了很大的存储开销的时候就
* 可以考虑是否可以使用享元模式。
* 例如,如果发现某个对象的生成了大量细粒度的实例,
* 并且这些实例除了几个参数外基本是相同的,如果把那些共享参数移到类外面,
* 在方法调用时将他们传递进来,就可以通过共享大幅度单个实例的数目。
*/