黑马程序员--java学习之享元与枚举

来源:互联网 发布:淘宝祛痘产品 编辑:程序博客网 时间:2024/06/06 09:14

---------------------- android培训、java培训、期待与您交流! ----------------------

一.享元模式

享元模式是一种软件设计模式它使用共享物件,用来尽可能减少内存使用量以及分享资讯给尽可能多的相似物件;它适合用于当大量物件只是重复因而导致无法令人接受的使用大量内存。通常物件中的部分状态是可以分享。常见做法是把它们放在外部数据结构,当需要使用时再将它们传递给享元。典型的享元模式的例子为文书处理器中以图形结构来表示字符。一个做法是,每字形其字型外观,字模 metrics,和其它格式资讯,但这会使每个字符就耗用上千字节。取而代之的是,每个字符参照到一个共享字形物件,此物件会被其它有共同特质的字符所分享;只有每个字符(文件中或页面中)的位置才需要另外储存。以下程式用来解释上述的文件例子。这个例子用来解释享元模式利用只载立执行立即小任务所必需的资料,因而减少内存使用量。 

享元:有很多个小的对象相同,有很多属性相同,把他们变成一个对象,不同的属性变成方法的参数,称为外部状态。

享元对象能做到共享的关键是区分内蕴状态(Internal State)和外蕴状态(External State)。 
     
一个内蕴状态是存储在享元对象内部的,并且不会随环境改变而有所不同的。因此,一个享元可以具有内蕴状态并可以共享。 
     
一个外蕴状态是随环境改变而改变的,不可以共享状态。享元对象的外蕴状态必须由客户端保存,并在享元对象被创建之后,在需要使用的时候再传到享元对象内部。 
     
外蕴状态不可以影响享元对象的内蕴状态,它们是相互独立的。所有的内蕴状态在对象创建完后就不可再改变。 

 

通俗易懂的例子:

在一个享元模式中,包括抽象的享元具体的享元享元工厂以及客户端。其中抽象的享元为公共接口或抽象类,具体的享元实现抽象享元角色所规定的接口,享元工厂负责创建和管理享元角色。

下面写了一个程序实现享元模式:包括抽象享元角色Person.java,两个具体享元角色OldFlyweight.javaYoungFlyweight.java,享元工厂FlyweightFactory.java,最后是一个客户端测试类ClientTest_Flyweight.java

package cn.pengpan.day1;/* *  * 需求:试着写一个享元模式的小程序 * 思路:简单的享元模式由抽象享元类,具体享元类,享元工厂类,享元客户端类组成 * 此为抽象享元类*/public abstract class Person {protected String personName;protected int personAge;public String getPersonName() {return personName;}public void setPersonName(String personName) {this.personName = personName;}public int getPersonAge() {return personAge;}public void setPersonAge(int personAge) {this.personAge = personAge;}public abstract void sayHello();}package cn.pengpan.day1;/* * 具体享元类 * */public class OlderFlyweight extends Person {public OlderFlyweight(int age){this.personAge=age;}public void sayHello(){System.out.println("hi,i am the older");}}package cn.pengpan.day1;/* * 具体享元类 * */public class YoungFlyweight extends Person {public YoungFlyweight(int age){this.personAge=age;}public void sayHello(){System.out.println("hi,i am the young");}}package cn.pengpan.day1;/* *  * 享元工厂类,用来让客户端得到需要的对象,用一个集合装入对象,若不存在,则创建装入,若存在则直接输出*/import java.util.*;public class FlyweightFactory {Hashtable AgedPersons=new Hashtable();public Person getFlyweight(int age){Person person=(Person)AgedPersons.get(age);if (person!=null) {if (age==person.getPersonAge()) { System.out.println("person-" + age + "被直接获取");}}if(person==null){switch (age) {case 25:person=new YoungFlyweight(25);break;case 80:person=new OlderFlyweight(80);default:break;}System.out.println("person-" + age + "新被创建");AgedPersons.put(age, person);}return person;}}package cn.pengpan.day1;public class FlyweightDemo { public static void main(String []args)  {  FlyweightFactory flyweightFactory = new FlyweightFactory();  //第一次测试,应该是直接创建  Person oldFlyweight1 = flyweightFactory.getFlyweight(80);  Person youngFlyweight1 = flyweightFactory.getFlyweight(25);  System.out.println(oldFlyweight1.getPersonAge());System.out.println(youngFlyweight1.getPersonAge());  //第二次测试,应该是直接获取  Person oldFlyweight2 = flyweightFactory.getFlyweight(80);Person youngFlyweight2 = flyweightFactory.getFlyweight(25); System.out.println(oldFlyweight2.getPersonAge()); System.out.println(youngFlyweight2.getPersonAge());      }}

二.枚举

      枚举(enum)类型是java5新增的特性,在没有枚举以前,java是通过在接口或者类中定义public static final 的变量来实现的,枚举就是要让某个类型的变量的取值只能为若干个固定值中的一个,否则,编译器就会报错。枚举可以让编译器在编译时就可以控制源程序中填写的非法值,普通变量的方式在开发阶段无法实现这一目标。

      为了更好的理解枚举这一概念,试写一个Weekday的普通类来模拟枚举的功能:

package cn.pengpan.day1;/* * 需求:用普通的java类来模拟枚举功能 * 思路;在枚举中,每一个枚举变量对象都是唯一的,故要用普通的类实现枚举功能必须保证每个枚举对象只能被创建 * 一次,故采用单例设计模式 *  * */public class WeekDay {private WeekDay(){}//私有主要作用是防止外部类生成其他的对象public static final WeekDay SUN_DAY=new WeekDay();//现成的两个对象,外部类直接用即可public static final WeekDay MON_DAY=new WeekDay();//public WeekDay getWeekDay(){if (this==SUN_DAY) {return MON_DAY;}else {return SUN_DAY;}}public String toString(){return this==SUN_DAY?"SUN_DAY":"MON_DAY";//ifesle高级语句,记住前面是一个BOOLEAN类型的值}}package cn.pengpan.day1;/* * 测试写好的模拟枚举类WeekDay * */public class WeekDayTest {public static void main(String[] args) {WeekDay test=WeekDay.MON_DAY;System.out.println(test.toString());}}

枚举的基本应用:

枚举就相当于一个类,其中也可以定义构造方法、成员变量、普通方法和抽象方法。枚举元素必须位于枚举体中的最开始部分,枚举元素列表的后要有分号与其他成员分隔。把枚举中的成员方法或变量等放在枚举元素的前面,编译器报告错误。

实例一:一个简单的带构造方法的枚举

public class WeekDayTest {public static void main(String[] args) {WeekDay1 test2=WeekDay1.TUE;System.out.println(test2.ordinal());//返回枚举常量的序数System.out.println(test2.name());//返回名称}public enum WeekDay1{SUN(1),MON(),TUE,WED,THI,FRI,SAT;private WeekDay1(){System.out.println("one");}//实现带有构造方法的枚举,必须是私有,而且构造方法必须在元素列表之后,防止外部类利用构造方法生成其他的枚举元素private WeekDay1(int day){System.out.println("two");}}}实例二:写一个带方法的枚举package cn.pengpan.day1;/* * 需求:定义一个枚举,模仿交通灯的交替颜色变换 * 思路:交通灯有三种颜色,故枚举有三个元素,每个元素应当调用父类的构造方法实现获得停顿时间属性,而 * 交替显示这个动作可以用元素的匿名子类覆盖父类抽象方法实现 * */public enum TrafficLamp {Yellow(50){public TrafficLamp nextLamp()//每个内部类覆盖抽象方法{return Red;}},Red(60){public TrafficLamp nextLamp(){return Green;}},Green(20){public TrafficLamp nextLamp(){return Yellow;}};private int time;public int getTime(){return this.time;}private TrafficLamp(int time){this.time=time;};//私有的构造方法,实现停顿时间参数的传递public abstract TrafficLamp nextLamp();}package cn.pengpan.day1;public class  TrafficLampTest{public static void main(String[] args) {TrafficLamp lamp1=TrafficLamp.Red;TrafficLamp lamp2=TrafficLamp.Yellow;TrafficLamp lamp3=TrafficLamp.Green;System.out.println(lamp1.nextLamp());System.out.println(lamp2.nextLamp());System.out.println(lamp3.nextLamp());System.out.println(lamp1.getTime());System.out.println(lamp2.getTime());System.out.println(lamp3.getTime());}}

---------------------- android培训、java培训、期待与您交流! ----------------------

原创粉丝点击