生産者・ブローカ・消費者のシミュレーション(パート3)

戻る

■実行結果

[資金残高] 生産者 =137.18       ブローカ =467.58        消費者1 = 11.13 消費者2 =388.40 消費者3 =284.78 地球の滋養 = 2.50

生産者 の倉庫内:[M][C][C][G][M][C][C][G][M][C][G][M][M][C][G][M][C][C][G]
ブローカ の倉庫内:[M][C][G][M][C][C][G][M][C][G]
消費者1 の倉庫内:[C][C][C][G][G][G]
消費者2 の倉庫内:[M]
消費者3 の倉庫内:

生産者 が [ Meat ] を生産しました! -- 製造コスト= 10.00
ブローカ から 消費者3 に Meat が販売されました。
Cerealが消費されました!

[資金残高] 生産者 =127.18       ブローカ =480.58        消費者1 = 11.13 消費者2 =388.40 消費者3 =279.78 地球の滋養 =-0.50

生産者 の倉庫内:[M][C][C][G][M][C][C][G][M][C][G][M][M][C][G][M][C][C][G][M]
ブローカ の倉庫内:[C][G][M][C][C][G][M][C][G]
消費者1 の倉庫内:[C][C][G][G][G]
消費者2 の倉庫内:[M]
消費者3 の倉庫内:[M]

*** 資源が枯渇しました!
生産者 から ブローカ に Meat が販売されました。
ブローカ から 消費者1 に Cereal が販売されました。
Meatが消費されました!

[資金残高] 生産者 =138.18       ブローカ =478.68        消費者1 =  2.03 消費者2 =388.40 消費者3 =279.78 地球の滋養 = 9.50

生産者 の倉庫内:[C][C][G][M][C][C][G][M][C][G][M][M][C][G][M][C][C][G][M]
ブローカ の倉庫内:[G][M][C][C][G][M][C][G][M]
消費者1 の倉庫内:[C][C][G][G][G][C]
消費者2 の倉庫内:
消費者3 の倉庫内:[M]

生産者 が [ Cereal ] を生産しました! -- 製造コスト=  8.75

[資金残高] 生産者 =129.43       ブローカ =478.68        消費者1 =  2.03 消費者2 =395.40 消費者3 =279.78 地球の滋養 = 0.75

生産者 の倉庫内:[C][C][G][M][C][C][G][M][C][G][M][M][C][G][M][C][C][G][M][C]
ブローカ の倉庫内:[G][M][C][C][G][M][C][G][M]
消費者1 の倉庫内:[C][C][G][G][G][C]
消費者2 の倉庫内:
消費者3 の倉庫内:[M]



::::::::::::::
Actor.java
::::::::::::::
import java.util.*;

/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

abstract public class Actor {
    /** 資金 */
    protected double fund;

    /** 名前 */
    protected String name;

    /** 在庫 */
    protected Stock stock;

    public Actor( String name, int stockSize ) {
        this.name = name;

        stock = new Stock( stockSize );
    }

    protected String getName() {
        return name;
    }

    /** 資金の初期値を設定する */
    protected void setFund( double fund ) {
        this.fund = fund;
    }

    /** 稼ぐ */
    protected void earnMoney( double amount ) {
        fund += amount;
    }

    /** 現在の資金情報を得る */
    protected double getFund() {
        return fund;
    }

    /** 資金を使う */
    protected void spendMoney( double cost ) {
        fund -= cost;
    }

    /** 購入するための資金に余裕があるか */
    protected boolean canAffordToBuy( double price ) {
        return ( fund >= price );
    }

    /** 在庫を取得する */
    protected Stock getStock() {
        return this.stock;
    }

    /** 在庫に追加可能かどうか */
    protected boolean isAcceptable() {
        return stock.isAcceptable();
    }

    /** 在庫内容をダンプする */
    protected void dumpStock() {
        System.out.print( this.name + " の倉庫内:" );

        Iterator iterator = stock.iterator();
        while ( iterator.hasNext() ) {
            Product product = ( Product ) iterator.next();
            String concreteProductName = product.getClass().getName();

            // クラス名のイニシャルのみ表示する
            System.out.print( "[" + concreteProductName.charAt( 0 ) + "]" );
        }
        System.out.println();
    }

    /** 入庫する */
    abstract public void stockup( Product product );
}
::::::::::::::
Broker.java
::::::::::::::
import java.util.*;

/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
@author KISHI Yasuhiro
*/

public class Broker extends Actor implements Drawable {

    public Broker( String name, int stockSize ) {
        super( name, stockSize );
    }

    /** 生産者より生産物を仕入れる */
    public void stockup( Product product ) {

        stock.store( product );

        // 資金を使う
        super.spendMoney( ProductPriceManager.getSellingPriceToBroker( product ) );
    }

    public static void main( String[] args ) throws Throwable {

        Producer producer = new Producer( "生産者", 20 );
        producer.setFund( 100.0 );

        Broker broker = new Broker( "ブローカ", 15 );
        broker.setFund( 200.0 );

        Consumer consumer1 = new Consumer( "消費者1", 8 );
        consumer1.setFund( 200.0 );

        Consumer consumer2 = new Consumer( "消費者2", 12 );
        consumer2.setFund( 800.0 );

        Consumer consumer3 = new Consumer( "消費者3", 20 );
        consumer3.setFund( 400.0 );


        // モニター対象者の設定
        Monitor monitor = new Monitor();
        monitor.addActor( producer );
        monitor.addActor( broker );
        monitor.addActor( consumer1 );
        monitor.addActor( consumer2 );
        monitor.addActor( consumer3 );

        monitor.printCurrentStatus();
        for ( int i = 0;i < 500;i++ ) {

            // 労働者の設定
            switch ( i % 3 ) {
            case 0:
                producer.setWorker( consumer1 );
                break;
            case 1:
                producer.setWorker( consumer2 );
                break;
            default:
                producer.setWorker( consumer3 );
                break;

            }
            producer.produce();

            if ( i % 2 == 0 ) {
                producer.sellProduct( broker );
            }

            if ( i % 3 == 0 ) {
                consumer1.buyProduct( broker );
                consumer2.consume();
            }
            if ( i % 5 == 0 ) {
                consumer2.buyProduct( broker );
                consumer3.consume();
            }
            if ( i % 7 == 0 ) {
                consumer3.buyProduct( broker );
                consumer1.consume();
            }

            monitor.printCurrentStatus();
            monitor.dumpStock();
        }
    }

}
::::::::::::::
Cereal.java
::::::::::::::
/**
* <pre>穀物</pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* 
*/

public class Cereal extends Product {

    private final double cost = 7.0;

    public Cereal( Producer producer ) {
        super( producer );
    }

    /** 現在の製造コストを返す */
    public double getCost() {
        return cost * ProductingCostManager.getCurrentRate();
    }

    static public void main( String[] args ) {}
}
::::::::::::::
Consumer.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
@author KISHI Yasuhiro
*/

public class Consumer extends Actor implements Drawable {

    public Consumer( String name, int stockSize ) {

        super( name, stockSize );
    }

    /** ブローカから商品を購入する */
    public void buyProduct( Broker broker ) throws Throwable {

        try {
            TransactionManager.transact( broker, this );
        } catch ( Throwable t ) {
            throw t;
        }
    }

    /** 生産者より生産物を仕入れる */
    public void stockup( Product product ) {

        stock.store( product );

        // 資金を使う
        super.spendMoney( ProductPriceManager.getSellingPriceToConsumer( product ) );
    }

    /**
    * 消費する
    */
    public void consume() {
        if ( !stock.isEmpty() ) {
            // 在庫が空でない場合
            try {
                Product product = ( Product ) stock.pickup();
                System.out.println( product.getClass().getName() + "が消費されました!" );

                // 土に戻る(養分として)
                Earth.getInstance().increaseNutrient( product.getCost() );

            } catch ( Throwable t ) {
                t.printStackTrace();
            }
        }
    }
}
::::::::::::::
Drawable.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

public interface Drawable {}
::::::::::::::
DrawingPanel.java
::::::::::::::
import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

import java.io.*;

import BasicPackage.*;

/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
@author KISHI Yasuhiro
*/

public class DrawingPanel extends AbstractDrawingPanel {

    public DrawingPanel() {
        super();
        start( 100 );
    }

    public void setActors() {}
    public void drawActors( Graphics g ) {}

    public void paintComponent( Graphics g ) {
        clearScreen( g );
    }

}

::::::::::::::
Earth.java
::::::::::::::
/**
<pre>地球をあらわすクラス(シングルトンである)</pre>
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
@author KISHI Yasuhiro
*/

public class Earth {

    /** インスタンス */
    static private Earth uniqueInstance;
    static private double nutrient;

    private Earth() {
        // インスタンス化
    }

    public static Earth getInstance() {
        if ( uniqueInstance == null ) {
            uniqueInstance = new Earth();
            nutrient = 300.0;
        }

        return uniqueInstance;
    }

    public synchronized void increaseNutrient( double value ) {
        nutrient += value;
    }
    public synchronized void decreaseNutrient( double value ) {
        nutrient -= value;
    }

    public synchronized double getNutrient() {
        return nutrient;
    }

    public static void main( String[] args ) {
        Earth earth = Earth.getInstance();

        System.out.println( "現在の養分は、" + earth.getNutrient() );

        earth.increaseNutrient( 10.5 );
        System.out.println( "現在の養分は、" + earth.getNutrient() );

        earth.decreaseNutrient( 50.5 );
        System.out.println( "現在の養分は、" + earth.getNutrient() );
    }
}
::::::::::::::
FactoryAutomation.java
::::::::::::::
import javax.swing.*;

import java.awt.*;
import java.awt.event.*;

import BasicPackage.*;

/**
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class FactoryAutomation extends AbstractJApplet {

    public FactoryAutomation() {
        setPanel( new DrawingPanel(), 800, 600 );

        init();
    }

}

::::::::::::::
GardenStuff.java
::::::::::::::
/**
* <pre>野菜</pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class GardenStuff extends Product {
    private final double cost = 5.0;

    public GardenStuff( Producer producer ) {
        super( producer );
    }

    /** 現在の製造コストを返す */
    public double getCost() {
        return cost * ProductingCostManager.getCurrentRate();
    }

}
::::::::::::::
Meat.java
::::::::::::::
/**
* <pre>食肉</pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* 
*/

public class Meat extends Product {

    private final double cost = 10.0;

    public Meat( Producer producer ) {
        super( producer );
    }

    /** 現在の製造コストを返す */
    public double getCost() {
        return cost * ProductingCostManager.getCurrentRate();
    }

    static public void main( String[] args ) {

        Meat meat = new Meat( new Producer( "山田さん", 6 ) );

        System.out.printf( "%5.2f\n", meat.getCost() );

    }
}
::::::::::::::
Monitor.java
::::::::::::::
import java.util.*;

/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

public class Monitor {

    private List list;

    public void addActor( Actor actor ) {
        if ( list == null ) {
            list = new LinkedList();
        }
        list.add( actor );
    }
    public void printCurrentStatus() {

        System.out.println();
        System.out.print( "[資金残高] " );

        Iterator iterator = list.iterator();
        while ( iterator.hasNext() ) {
            Actor actor = ( Actor ) iterator.next();
            System.out.printf( "%s =%6.2f\t", actor.getName(), actor.getFund() );
        }

        System.out.printf( "地球の滋養 =%5.2f", Earth.getInstance().getNutrient() );
        System.out.println();
    }

    public void dumpStock() {

        System.out.println();
        Iterator iterator = list.iterator();
        while ( iterator.hasNext() ) {
            Actor actor = ( Actor ) iterator.next();
            actor.dumpStock();
        }

        System.out.println();
    }

}
::::::::::::::
Producer.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
@author KISHI Yasuhiro
*/

public class Producer extends Actor implements Drawable {

    /** 労働者 */
    private Actor worker;

    public Producer( String name, int stockSize ) {
        super( name, stockSize );
    }

    /** 労働者を設定する */
    public void setWorker( Actor worker ) {
        this.worker = worker;
    }

    public void produce() {

        if ( Earth.getInstance().getNutrient() <= 0.0 ) {
            System.out.println( "*** 資源が枯渇しました!" );
            return ;
        }

        if ( !this.isAcceptable() ) {
            System.out.println( "--- " + this.getName() + "は、これ以上在庫を増やすことは出来ません。" );
            return ;
        }

        // 市場の動向に従い生産物を決める
        Product product = ( Product ) TrendInformationProvider.notifyHotSellingProduct( this );

        if ( ! canAffordToProduce( product.getCost() ) ) {
            System.out.println( "--- " + this.getName() + "は、もう資金に余裕がありません!" );
            return ;
        }

        //--------------------------------------
        // 資金を使う(製造コスト分)
        //--------------------------------------
        super.spendMoney( product.getCost() );

        //----------------------------------------------------------------------------
        // 製造コストのうち、8割が労働力によるものとして、その分を労働者に支払う
        //----------------------------------------------------------------------------
        if ( worker == null ) {
            // 労働者が指定されていない場合は、自分自身が労働者である
            worker = this;
        }
        worker.earnMoney( product.getCost() * 0.8 );

        // 地球の養分を使う(材料費はタダ)
        Earth.getInstance().decreaseNutrient( product.getCost() );

        System.out.printf( "%s が [ %s ] を生産しました! -- 製造コスト=%6.2f\n",
                           this.getName(), product.getClass().getName(), product.getCost() ) ;

        // 生産物を在庫に格納
        stock.store( product );


    }

    /** 生産するための資金に余裕があるか */
    private boolean canAffordToProduce( double cost ) {
        return ( fund >= cost );
    }

    public void stockup( Product product ) {
        /** DO NOTHING */
    }

    /**
    * 生産物をブローカに販売する 
    * 販売する生産物は、キューの先頭に入っているものとする
    * 取引自体はTransactionManagerに処理を委譲する
    */
    public void sellProduct( Broker broker ) throws Throwable {

        try {
            TransactionManager.transact( this, broker );

        } catch ( Throwable t ) {
            throw t;
        }
    }

    /** 単体テスト */
    static public void main( String[] args ) throws Throwable {

        Producer producer = new Producer( "大山さん", 5 );
        producer.setFund( 100.0 );

        for ( int i = 0;i < 15;i++ ) {
            producer.produce();
            System.out.printf( "現在の資金残高=%6.2f\n", producer.getFund() );

            try {
                Thread.sleep( 500 );
            } catch ( Throwable t ) {
                throw t;
            }
        }

        System.out.println( "-------------------------------------------------------------------" );

        Producer producer2 = new Producer( "藤田さん", 10 );
        producer2.setFund( 40.0 );

        for ( int i = 0;i < 15;i++ ) {
            producer2.produce();
            System.out.printf( "現在の資金残高=%6.2f\n", producer2.getFund() );

            try {
                Thread.sleep( 500 );
            } catch ( Throwable t ) {
                throw t;
            }
        }
    }
}
::::::::::::::
Product.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

abstract public class Product {
    protected Producer producer;

    public Product( Producer producer ) {
        this.producer = producer;
    }

    /**
    * 季節によりコストが変更するものとする 
    */
    abstract double getCost();
}
::::::::::::::
ProductPriceManager.java
::::::::::::::
/**
* <pre>
* とりあえず現時点での流通経路は、生産者→ブローカ→消費者のみ
* ブローカ→ブローカの流れはないものとする
* </pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class ProductPriceManager {

    static double getSellingPriceToBroker( Product product ) {
        return 1.1 * product.getCost();
    }

    static double getSellingPriceToConsumer( Product product ) {
        return 1.3 * product.getCost();
    }

}
::::::::::::::
ProductingCostManager.java
::::::::::::::
/**
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* 製造コストの季節変動の割合を返す
*/

public class ProductingCostManager {

    static public double getCurrentRate( ) {

        // ロジックはあとで変更する
        if ( System.currentTimeMillis() % 5 == 0 ) {
            return 1.25;
        } else {
            return 1.00;
        }
    }

}
::::::::::::::
Stock.java
::::::::::::::
import java.util.*;
import java.util.concurrent.*;

/**
* <pre>在庫エンティティ</pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class Stock implements Storable {

    private int size;
    private ArrayBlockingQueue queue;

    public Stock( int size ) {
        this.size = size;
        queue = new ArrayBlockingQueue( size );
    }

    /** キューにデータを格納する */
    public void store( Object obj ) {
        boolean status = queue.offer( obj );

    }

    /** キューの先頭データを参照する(削除はしない)*/
    public Object peek() {
        return queue.peek();
    }

    /** キューからデータを取り出す */
    public Object pickup() throws Throwable {
        Object object;
        try {
            object = queue.take();
        } catch ( Throwable t ) {
            throw t;
        }

        return object;
    }

    /** 追加可能かどうか */
    public boolean isAcceptable() {
        // System.out.println( "現在の在庫数=" + queue.size() + " : 許容サイズ=" + size );
        return ( queue.size() != size );
    }

    /** キューが空かどうか */
    public boolean isEmpty() {
        return ( queue.size() == 0 );
    }

    public Iterator iterator() {
        return queue.iterator();
    }

}
::::::::::::::
Storable.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

public interface Storable {

    /** 格納する */
    public void store( Object obj );

    /** 取り出す */
    public Object pickup() throws Throwable;

    /** 先頭要素を参照する */
    public Object peek();

    /** 追加可能かどうか */
    public boolean isAcceptable();

    /** キューが空かどうか */
    public boolean isEmpty();
}
::::::::::::::
TransactionManager.java
::::::::::::::
/**
* <pre>
* 抽象クラスActorを継承したクラス(Prpducer, Broker, Consumer)同士のトランザクションを代行するクラス
* お互いに他のオブジェクトを直接CALLしないようにしてクラス間の依存性を極力少なくする(→疎結合)
* </pre>
* $Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
* @author KISHI Yasuhiro
*/

public class TransactionManager {

    static public synchronized void transact( Actor seller, Actor buyer )
    throws Throwable {

        Stock stock = seller.getStock();

        if ( stock.isEmpty() ) {
            System.out.println( "/******/ " + seller.getName() + "の生産在庫が空ですので取引できません。" );
            return ;
        }

        Product product;
        try {
            // 在庫内の先頭要素を参照する
            product = ( Product ) stock.peek();

        } catch ( Throwable t ) {
            throw t;
        }

        String className = buyer.getClass().getName();
        double price = 0.0;
        if ( "Broker".equals( className ) ) {
            price = ProductPriceManager.getSellingPriceToBroker( product );
        }
        if ( "Consumer".equals( className ) ) {
            price = ProductPriceManager.getSellingPriceToConsumer( product );
        }

        // 買い手に購入資金がない場合は、取引しないまま終了
        if ( !buyer.canAffordToBuy( price ) ) {
            System.out.println( "--- " + buyer.getName() + "に購入資金がありません!" );
            return ;
        }

        // 買い手の在庫が満杯の場合は、取引しないまま終了
        if ( !buyer.isAcceptable() ) {
            System.out.println( "--- " + buyer.getName() + "の在庫が満杯です!" );
            return ;
        }

        try {
            // キューから生産物を取り出す
            product = ( Product ) stock.pickup();

            // 買い手が入荷する
            buyer.stockup( product );

            // 入金する
            double currentFund = seller.getFund();
            seller.setFund( currentFund + price );

            // 取引内容をダンプする
            System.out.println( seller.getName() + " から " + buyer.getName() + " に "
                                + product.getClass().getName() + " が販売されました。" );

        } catch ( Throwable t ) {
            throw t;
        }

    }

}
::::::::::::::
TrendInformationProvider.java
::::::::::::::
/**
$Id: FA3.html,v 1.1 2009/06/22 16:11:43 kishi Exp kishi $
*/

public class TrendInformationProvider {

    static public Product notifyHotSellingProduct( Producer producer ) {

        // ロジックはあとで変更する
        int mod = ( int ) ( System.currentTimeMillis() % 4 ) ;
        if ( mod == 0 ) {
            return new Meat( producer );
        } else if ( mod == 1 ) {
            return new GardenStuff( producer );
        } else {
            return new Cereal( producer );
        }

    }
}




戻る inserted by FC2 system